3

I have a function like so:

public List<T> SelectAll<T>() where T : DatabaseObject, new()
{
    List<T> retVal = new List<T>();
    String command = "Select * from " + GetType().Name;
    MySqlCommand cmd = DatabaseRunner.GetCommand(command);
    MySqlDataReader reader = cmd.ExecuteReader();
    while (reader.Read())
    {
        T newObj = new T(reader);
    }
    return retVal;
}

You can see when I try to create a new T object, I pass in a MySqlDataReader object to the constructor. How can I modify the method signature to allow this?

1
  • You can cheat, let T implement an interface containing a single factory method which creates a new T and takes an argument. Kind of ugly, but it beats reflection IMO. Commented Oct 14, 2011 at 19:13

3 Answers 3

9

You cannot. C# only supports the new() constraint (which you're already using) for constraining the type parameter to types with a parameterless constructor. Constructors with parameters are not supported in this context.

Sign up to request clarification or add additional context in comments.

1 Comment

I would suggest instead what you want is an interface that has a parameter which takes a SqlDataReader and reads (and initializes) the object as necessary.
8

Short answer is you can't. One way around this is to remove the new() constraint and use Activator.CreateInstance():

T value = (T) Activator.CreateInstance(typeof(T), reader)

1 Comment

Remember to cast the result to T.
7

You can't do this with a constraint. However, you can call the method and pass in a function to create a T from a MySqlDataReader:

public List<T> SelectAll<T>(Func<MySqlDataReader, T> projection)
    where T : DatabaseObject
{
    List<T> retVal = new List<T>();
    String command = "Select * from " + GetType().Name;
    MySqlCommand cmd = DatabaseRunner.GetCommand(command);
    MySqlDataReader reader = cmd.ExecuteReader();
    while (reader.Read())
    {
        retValue.Add(projection(reader));
    }
    return retVal;
}

(You may well want to use DbDataReader instead of MySqlDataReader to avoid being so specific.)

Another alternative is to give DatabaseObject something like an Initialize(DbDataReader reader) method, then you could use:

public List<T> SelectAll<T>() where T : DatabaseObject, new()
{
    List<T> retVal = new List<T>();
    String command = "Select * from " + GetType().Name;
    MySqlCommand cmd = DatabaseRunner.GetCommand(command);
    MySqlDataReader reader = cmd.ExecuteReader();
    while (reader.Read())
    {
        T value = new T();
        value.Initialize(reader);
        retValue.Add(value);
    }
    return retVal;
}

As a side issue, you're not disposing of anything - you should really be using using statements to dispose of the reader and the command automatically.

1 Comment

I just finished writing IDENTICAL code a second ago! Good answer :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.