views:

210

answers:

2

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;
    }
}
+3  A: 

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();
AnthonyWJones
Thats exactly what i was missing!It even worked in VB.net :)
Pondidum
+1  A: 

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.

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