如何迭代List <t>其中T:MyClass </t>

时间:2013-10-22 09:09:27

标签: c# list loops

我有嵌套列表的实体:

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
  • ,如何迭代列表

P.S

我正在使用.NET 4.5

5 个答案:

答案 0 :(得分: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继承的,并且您已确定它是一个列表(来自上一个问题),那么最简单的选项是{{1} }和IList

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

答案 1 :(得分:3)

如何将属性类型与List<T>进行比较:

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

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

var listForIteration = (IEnumerable<EntityBase>)list;

foreach (var item in listForIteration)
{
}

List<T>不是协变的,但是(从.NET 4.0开始)IEnumerable<T>是。{/ p>

更新:在发表一些评论之后,这里是您没有问过的问题的答案:

如何测试我是否可以将对象枚举为从EntityBase继承的项目序列,如果是,则循环遍历它:

var listForIteration = list as IEnumerable<EntityBase>;

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

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

答案 2 :(得分:1)

你可能想要像

这样的东西
Type type = p.PropertyType;
if(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>) &&
   typeof(EntityBase).IsAssignableFrom(type.GetGenericArguments()[0]))
{
    // iterate list
}

答案 3 :(得分: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
    }
}

答案 4 :(得分:0)

  

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

你知道它是EntityBase类型的子类,所以不是使用泛型,为什么不去寻找一个好的旧超类引用呢?然后,在List<EntityBase>做得很好的情况下,不需要在这种情况下使用泛型。