3

我有嵌套列表的实体:

public class Article : MyEntityBase
{
    public Article()
    {
        Tags = new List<Tag>();
    }

    [MyAttribute]
    public string Title { get; set; }

    [MyAttribute]
    public virtual List<Tag> Tags { get; set; }
}

public class Tag : EntityBase
{
    public string Title { get; set; }
}

public abstract class MyEntityBase
{
    public Guid Id { get; set; }
}

我也有收集所有[MyAttribute]标记属性并对其进行操作的功能:

public function OperateWithAttributes(IEnumerable<PropertyInfo> properties)
{
    foreach (var p in properties)
    {
        if (p.PropertyType == typeof(string))
        {
            // do something
        }
        else if (/* there are code that check property type is List<T> */)
        {
            /* there are code that iterate list */
        }
    }
}

问题:

  • 如何比较属性类型List<T>
  • 如果我知道它是继承自的,如何迭代列表EntityBase

附言

我正在使用 .NET 4.5

4

5 回答 5

4

如何比较属性类型List<T>

正确地将某些东西识别为列表是……棘手的;特别是如果您想处理所有边缘情况(自定义IList<Foo>实现或子类List<T>等的类)。许多框架代码检查“实现非泛型IList,并具有非object索引器”:

    static Type GetListType(Type type)
    {
        if (type == null) return null;
        if (!typeof(IList).IsAssignableFrom(type)) return null;

        var indexer = type.GetProperty("Item", new[] { typeof(int) });
        if (indexer == null || indexer.PropertyType == typeof(object))
            return null;

        return indexer.PropertyType;
    }

如果我知道它是继承自的,如何迭代列表EntityBase

假设您的意思是这些项目是从 继承的EntityBase,并且您已经确定它是一个列表(来自上一个问题),那么最简单的选择是IListand foreach

var itemType = GetListType(p.PropertyType);
if(itemType != null && itemType.IsSubclassOf(typeof(EntityBase)))
{
    var list = (IList) p.GetValue(obj);
    foreach(EntityBase item in list)
    {
        // ...
    }
}

注意:如果您仍然要获取该值您也可以将其反转并在使用之前使用is测试:GetListType

var value = p.GetValue(obj);
Type itemType;
if(value is IList && (itemType = GetListType(p.PropertyType) != null)
      && itemType.IsSubclassOf(typeof(EntityBase)))
{
    var list = (IList)value;
    foreach(EntityBase item in list)
    {
        // ...
    }
}
于 2013-10-22T09:22:39.193 回答
3

如何比较属性类型List<T>

if (p.PropertyType.IsGenericType && 
    p.PropertyType.GetGenericTypeDefinition() == typeof(List<>))

如果我知道 [其项目是] 从 EntityBase 继承的,如何迭代列表:

var listForIteration = (IEnumerable<EntityBase>)list;

foreach (var item in listForIteration)
{
}

AList<T>不是协变的,但(从 .NET 4.0 开始) anIEnumerable<T>是。

更新:经过一些评论,这里是你没有问的问题的答案:

如何测试我是否可以将一个对象枚举为从 EntityBase 继承的一系列项目,如果可以,则对其进行循环:

var listForIteration = list as IEnumerable<EntityBase>;

if (listForIteration != null)
{
    foreach (var item in listForIteration)
    {
    }
}

这将(在 .NET 4.0 或更高版本上)允许您迭代 EntityBase(或派生)对象的任何集合,即使该集合不是 a List<>(除了那些不实现IEnumerable<T>的,但那些很少见)。

于 2013-10-22T09:21:48.197 回答
1

你可能想要类似的东西

Type type = p.PropertyType;
if(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>) &&
   typeof(EntityBase).IsAssignableFrom(type.GetGenericArguments()[0]))
{
    // iterate list
}
于 2013-10-22T09:20:08.150 回答
1

如果只想迭代列表,可以使用IEnumerable<out T>的协方差:

if (typeof(IEnumerable<EntityBase>).IsAssignableFrom(p.PropertyType))
{
    var enumerable = (IEnumerable<EntityBase>)p.GetValue(obj);
    foreach (var entity in entities)
    {
        // do something
    }
}
于 2013-10-22T09:26:13.760 回答
0

如果我知道它是从 EntityBase 继承的,如何迭代列表?

你知道它是 type 的子类EntityBase,所以不要使用泛型,为什么不去寻找一个好的旧的超类参考呢?那么在这种情况下就不需要使用泛型了,什么时候List<EntityBase>就可以了。

于 2013-10-22T09:16:43.173 回答