[英]How to iterate List<T> where T: MyClass
I have entity with nested list: 我有嵌套列表的实体:
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; }
}
Also I have function that collects all [MyAttribute]
marked properties and do something operations with them: 此外,我还有一个函数,它收集所有
[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>
? List<T>
? EntityBase
? EntityBase
继承的,如何迭代列表? I'm using .NET 4.5 我正在使用.NET 4.5
How to compare property type with
List<T>
?如何比较属性类型与
List<T>
?
Correctly identifying something as a list is ... tricky; 正确地将某事物识别为列表是......棘手的; especially if you want to handle all edge-cases (a custom
IList<Foo>
implementation, or a class that subclasses List<T>
, etc). 特别是如果你想处理所有边缘情况(自定义
IList<Foo>
实现,或者子类List<T>
类等)。 A lot of framework code checks instead for "implements the non-generic IList
, and has a non- object
indexer": 许多框架代码检查“实现非通用
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;
}
How to iterate list if I know that it's inherited from
EntityBase
?如果我知道它是从
EntityBase
继承的,如何迭代列表?
Assuming you mean that the items are inherited from EntityBase
, and you have determined that it is a list (from the previous question), then the easiest option is IList
and foreach
: 假设你的意思是这些项是从
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)
{
// ...
}
}
Note: if you are going to get the value anyway , you can also reverse this and use an is
test before using GetListType
: 注意:如果你打算无论如何要得到值,还可以扭转这种和使用
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)
{
// ...
}
}
How to compare property type with List<T>
: 如何比较属性类型与
List<T>
:
if (p.PropertyType.IsGenericType &&
p.PropertyType.GetGenericTypeDefinition() == typeof(List<>))
How to iterate list if I know that [its items are] inherited from EntityBase: 如果我知道[其项目]是从EntityBase继承的,如何迭代列表:
var listForIteration = (IEnumerable<EntityBase>)list;
foreach (var item in listForIteration)
{
}
A List<T>
is not covariant, but (as of .NET 4.0) an IEnumerable<T>
is. List<T>
不是协变的,但是(从.NET 4.0开始) IEnumerable<T>
是。
UPDATE : After some comments, here's an answer to the question you didn't ask: 更新 :经过一些评论,这里是你没有问过的问题的答案:
How to test if I can enumerate an object as a sequence of items that inherit from EntityBase, and if so, loop over it: 如何测试我是否可以将对象枚举为从EntityBase继承的项目序列,如果是,则循环遍历它:
var listForIteration = list as IEnumerable<EntityBase>;
if (listForIteration != null)
{
foreach (var item in listForIteration)
{
}
}
This will (on .NET 4.0 or later) allow you to iterate any collection of EntityBase (or derived) objects, even if the collection is not a List<>
(except for those that don't implement IEnumerable<T>
, but those are rare). 这将(在.NET 4.0或更高版本上)允许您迭代任何EntityBase(或派生)对象的集合,即使该集合不是
List<>
(除了那些没有实现IEnumerable<T>
那些,但那些很少见)。
You probably want something like 你可能想要这样的东西
Type type = p.PropertyType;
if(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>) &&
typeof(EntityBase).IsAssignableFrom(type.GetGenericArguments()[0]))
{
// iterate list
}
If you only want to iterate the list, you can use IEnumerable<out T>
's covariance: 如果您只想迭代列表,可以使用
IEnumerable<out T>
的协方差:
if (typeof(IEnumerable<EntityBase>).IsAssignableFrom(p.PropertyType))
{
var enumerable = (IEnumerable<EntityBase>)p.GetValue(obj);
foreach (var entity in entities)
{
// do something
}
}
How to iterate list if I know that it's inherited from EntityBase?
如果我知道它是从EntityBase继承的,如何迭代列表?
You know it's a subclass of type EntityBase
, so instead of using generics, why not just go for a good old superclass reference? 你知道它是
EntityBase
类型的子类,所以不是使用泛型,为什么不去寻找一个好的旧超类引用呢? Then there's no need to use generics in this scenario, when List<EntityBase>
will do fine. 然后在这种情况下,当
List<EntityBase>
良好时,不需要使用泛型。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.