Daniel Williams
Daniel Williams

Reputation: 9314

Collection of Generic Lists

I have a function which needs to go through a class' types and identify a specific type. If I find that type, I want to cast it to the type that I know it is. But in the code below, the following case is failing:

 BaseTableObjectList<BaseTableObject> obj = pi.GetValue(item, null) as BaseTableObjectList<BaseTableObject>;

Here is the code. Basically, I am making an iterator which returns certain properties. Why can't I cast?

foreach (PropertyInfo pi in item.GetType().GetProperties())
{
  if (pi.PropertyType.BaseType == null) continue; // skip interfaces
  if (!pi.PropertyType.BaseType.IsGenericType) continue;  // only interested in childlists

  Type[] types = pi.PropertyType.BaseType.GetGenericArguments();
  // is my generic argument derived from baseObject?
  if (typeof(BaseTableObject).IsAssignableFrom(types[0]))
  {
    // this is a child we want
    log.Info(types[0].Name);
    BaseTableObjectList<BaseTableObject> obj = pi.GetValue(item, null) as BaseTableObjectList<BaseTableObject>;
    yield return obj;
  }
}

Upvotes: 3

Views: 121

Answers (2)

Tomislav Markovski
Tomislav Markovski

Reputation: 12366

Make sure that pi.GetValue(item, null).GetType() is actually the type you want to cast to. It seems like it returns BaseTableObject instead BaseTableObjectList<BaseTableObject>

If your class Company : BaseTableObject and your CompanyList : BaseTableObjectList<Company> then your result can be cast to BaseTableObjectList<BaseTableObject> by using CompanyList.Cast<BaseTableObject>()

Edit2: From your comments, I think the following code will do the work.

BaseTableObjectList<BaseTableObject> obj = new BaseTableObjectList<BaseTableObject>((pi.GetValue(item, null) as System.Collections.IEnumerable).Cast<BaseTableObject>());

Upvotes: 2

Paul Tyng
Paul Tyng

Reputation: 7584

The problem you have I think is one of covariance, which only applies to interfaces. If you had a IBaseTableObjectList<out T> where T : BaseTableObject the cast wouldn't fail. Covariance for generics is only supported on delegates and interfaces not on base classes:

http://blogs.msdn.com/b/csharpfaq/archive/2010/02/16/covariance-and-contravariance-faq.aspx

In C#, variance is supported in the following scenarios:

  • Covariance in arrays (since C# 1.0)
  • Covariance and contravariance in delegates, also known as “method group variance” (since C# 2.0)
  • Variance for generic type parameters in interfaces and delegates (since C# 4.0)

This is essentially the same problem is assigning a List<string> to an IEnumerable<object> which is one of the examples in the linked article.

Upvotes: 1

Related Questions