Question

I'm trying to implement a helper method using generics (C# / 3.5) I've a nice structure of classes, with base classes like so:

public class SomeNiceObject : ObjectBase
{
  public string Field1{ get; set; }
}

public class CollectionBase<ObjectBase>()
{
  public bool ReadAllFromDatabase();
}

public class SomeNiceObjectCollection : CollectionBase<SomeNiceObject>
{

}

And I wish to retreive collection using a generic method like so:

    public class DAL
    {

     public SomeNiceObjectCollection Read()
     {
      return ReadFromDB<SomeNiceObjectCollection>();
     }

     T ReadFromDB<T>() where T : CollectionBase<ObjectBase>, new()
     {
      T col = new T();
      col.ReadAllFromDatabase();
      return col;          
     }
   }

This doesn't build, with

Error   66  The type 'SomeNiceObjectCollection' cannot be used as type parameter 'T' in the generic type or method 'ReadFromDB<T>'.   There is no implicit reference conversion from 'SomeNiceObjectCollection' to 'CollectionBase<ObjectBase>'.

The SomeNiceObjectCollection object IS a CollectionBase, a CollectionBase to be exact. So how I can get this to work?

Was it helpful?

Solution

C# doesn't support casting between list types (covariance).

Your best bet to support this pattern would be to introduce an interface for the ReadAllFromDatabase method so you are not relying on a generic collection:

public class SomeNiceObject : ObjectBase
{
  public string Field1{ get; set; }
}

public interface IFromDatabase
{
  bool ReadAllFromDatabase();
}

public class CollectionBase<ObjectBase>() : IFromDatabase
{
  public bool ReadAllFromDatabase();
}

public class SomeNiceObjectCollection : CollectionBase<SomeNiceObject>
{

}

public class DAL
{

 public SomeNiceObjectCollection Read()
 {
  return ReadFromDB<SomeNiceObjectCollection>();
 }

 T ReadFromDB<T>() where T : IFromDatabase, new()
 {
  T col = new T();
  col.ReadAllFromDatabase();
  return col;          
 }
}

OTHER TIPS

In C# 3.0 this is not possible, but with C# and .NET 4.0 with covariance and contravariance, this might be possible.

Think about it, you're taking a collection containing a derived object, and trying to temporarily treat it as a collection of the base object. If this was allowed, you could insert base objects into the list, which would not be of the derived object.

Here, an example:

List<String> l = new List<String>();
List<Object> o = l;
l.Add(10); // 10 will be boxed to an Object, but it is not a String!
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top