如何迭代List其中T:MyClass
本文关键字:其中 MyClass List 何迭代 迭代 | 更新日期: 2023-09-27 18:36:31
我有带有嵌套列表的实体:
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
如何比较房产类型与
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
继承的,并且你已经确定它是一个列表(来自上一个问题),那么最简单的选择是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)
{
// ...
}
}
注意:如果您无论如何都要获得该值,您也可以反转此操作并在使用GetListType
之前使用is
测试:
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<>))
如果我知道[它的项]是从实体库继承的,如何迭代列表:
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
的子类,所以与其使用泛型,为什么不直接去找一个好的旧超类引用呢?那么在这种情况下就不需要使用泛型,当List<EntityBase>
可以正常工作时。