Friday, May 6, 2011

Generic collection loading from the generic type

I have the following code, where i am trying to create a generic collection for the objects in my DAL (just an exercise, not actually production code). My problem is that i want to use the type passed in's Read method (which is part of an interface that the classes implement).

I cannot create a new T so i dont have an instance of the object to work with, and i cant declare it as the base type, as i need the read method specified by the child of the base object.

Is this actually possible or am i barking up the wrong tree?

public class ItemDictionary<T> where T : ILoadable, DataItem
{

    public void Load()
    {
        using (IDataReader reader = SqlHelper.ExecuteReader(_connection, CommandType.StoredProcedure, _proc)) {
            Read(reader);
        }
    }

    bool Read(IDataReader reader)
    {
        while (reader.Read) 
     {
            T item = default(T);            //Here be the problem

            if (item.Read(reader)) 
      {
                this.Add(item.Guid, item);
            }
        }

        return true;
    }

}

public class ExampleObject : DataItem, ILoadable
{

    bool Read(IDataReader reader)
    {
        _var1 = reader.getString(0);
        _var2 = reader.getString(1);
        _var3 = reader.getString(2);

     return true;
    }
}
From stackoverflow
  • Can you not have a default constructor on the type(s) held by the collection and add the new() directive to the where T : directive?

    public class ItemDictionary<T> where T : ILoadable, DataItem, new()
    

    and then:-

        T item = new T();
    
    Pondidum : Thats exactly what i was missing! It even worked in VB.net :)
  • It's not clear to me why you can't use new T() (with an appropriate constraint on T). It's also not clear to me why you're using explicit interface implementation, and why your ILoadable interface has a method called ILoadable, mind you.

    Is the problem that you can't always guarantee to have a parameterless constructor in the object type? If that's the case, you'll certainly need something to create instances of T. Perhaps you actually need to separate T from its factory, perhaps with another interface:

    public interface IFactory<T>
    {
        // Roughly matching your current API
        bool TryRead(IDataReader reader, out T);
    
        // Simpler if you can just throw an exception on error
        T Read(IDataReader reader);
    }
    

    Then you can just pass an IFactory<T> implementation into your ItemDictionary<T> constructor.

    Pondidum : Sorry, converted this form vb.net with an online code converter...

0 comments:

Post a Comment