繁体   English   中英

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

[英]How to iterate List<T> where T: MyClass

我有嵌套列表的实体:

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继承的,如何迭代列表?

PS

我正在使用.NET 4.5

如何比较属性类型与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继承的,并且你已经确定它是一个列表(来自上一个问题),那么最简单的选项是IListforeach

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)
    {
        // ...
    }
}

如何比较属性类型与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>是。

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

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

var listForIteration = list as IEnumerable<EntityBase>;

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

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

你可能想要这样的东西

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

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

if (typeof(IEnumerable<EntityBase>).IsAssignableFrom(p.PropertyType))
{
    var enumerable = (IEnumerable<EntityBase>)p.GetValue(obj);
    foreach (var entity in entities)
    {
        // do something
    }
}

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

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

为什么我不能从列表中投射<myclass>列出<object> ?<div id="text_translate"><p> 我有一个对象列表,它们属于我的QuoteHeader类型,我想将此列表作为对象列表传递给能够接受List&lt;object&gt;的方法。</p><p> 我的代码行显示...</p><pre> Tools.MyMethod((List&lt;object&gt;)MyListOfQuoteHeaders);</pre><p> 但是我在设计时收到以下错误...</p><pre> Cannot convert type 'System.Collections.Generic.List&lt;MyNameSpace.QuoteHeader&gt;' to 'System.Collections.Generic.List&lt;object&gt;'</pre><p> 我需要对我的 class 做任何事情来允许这样做吗? 我认为所有类都继承自 object 所以我不明白为什么这不起作用?</p></div></object></myclass>

[英]Why can't I cast from a List<MyClass> to List<object>?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM