转换为通用基类型

时间:2013-12-17 11:10:44

标签: c# generics reflection casting

我有以下类结构:

public class RelationBase : Entity
{
}

public class RelationURL : RelationBase
{
}

public class RelationBaseList<T> where T: RelationBase
{
  public List<T> Collection { get; set; }
}

public class RelationURLList : RelationBaseList<RelationURL>
{
}

public class RefTest
{
  public RelationURLList urlList { get; set; }

  public RefTest()
  {
    urlList = new RelationURList();
    urlList.Collection = new List<RelationUR>();
    urlList.Collection.Add(new RelationUR());
  }
}

通过反射,我得到一个RelationURLList的实例,我想把它转换为RelationBaseList<RelationBase>。不幸的是,我只能将它投射到RelationBaseList<RelationURL>

RefTest obj = new RefTest();
PropertyInfo[] props = obj.GetType().GetProperties();
foreach (PropertyInfo prop in props)
{
  object PropertyValue = prop.GetValue(obj, null);

  object cast1 = PropertyValue as RelationBaseList<RelationURL>;
  object cast2 = PropertyValue as RelationBaseList<RelationBase>;
}

在cast1中,我有预期的对象,但cast2为null。因为我不想从RelationBase转换到每个可能派生的类,所以我想使用第二个转换(cast2)。任何想法,如何获得对象,而不是转换为每个派生类型?

2 个答案:

答案 0 :(得分:3)

你不能。

编译器无法验证您所做的事情是否合法。

如果RelationBaseList是一个接口,您可以使用out关键字标记泛型参数,以表示该接口仅允许检索来自该对象的数据。< / p>

但是,您的代码组织方式,编译器无法验证您是否尝试这样做:

case2.Add(new SomeOtherRelationObject());

并且泛型的全部意义是使类型安全的代码。

所以不,你做不到。

答案 1 :(得分:1)

你想用RelationBaseList.Collection 做什么

如果您只想访问Collection的值而不是设置它们,那么使用接口可能是一种可能的解决方案:

public interface IRelationBaseList
{
    IEnumerable<RelationBase> Collection { get; }
}

public class RelationBaseList<T> : IRelationBaseList where T : RelationBase
{
    IEnumerable<RelationBase> IRelationBaseList.Collection
    {
        get { return Collection; }
    }
    public List<T> Collection { get; set; }
}

public class RelationURLList : RelationBaseList<RelationURL>
{

}

所以你可以这样做:

RefTest obj = new RefTest();
PropertyInfo[] props = obj.GetType().GetProperties();
foreach (PropertyInfo prop in props)
{
    object PropertyValue = prop.GetValue(obj, null);

    var relationBaseList = PropertyValue as IRelationBaseList;
    foreach (var relationBase in relationBaseList.Collection)
    { 
        // do something with it
    }
}