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:
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
? I'm using .NET 4.5
How to compare property type with
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). A lot of framework code checks instead for "implements the non-generic IList
, and has a non- object
indexer":
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
?
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
:
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
:
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>
:
if (p.PropertyType.IsGenericType &&
p.PropertyType.GetGenericTypeDefinition() == typeof(List<>))
How to iterate list if I know that [its items are] inherited from 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.
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:
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).
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:
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?
You know it's a subclass of type EntityBase
, so instead of using generics, why not just go for a good old superclass reference? Then there's no need to use generics in this scenario, when List<EntityBase>
will do fine.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.