Generics inheritance problem using reflection
here is my problem: I am modifying a framework developed in my company, and we have a function that returns any changes in a class' properties. This is the structure in the framework:
namespace Fwk.Business.Entities
public class BusinessEntity : IIdentifiable, ICloneableExt
{
...
}
public class EntityList<BE> where BE : BusinessEntity, new()
{
...
}
}
and this is a tipical use:
namespace Common.Business.Entities
{
public class ImportFileEntity : Fwk.Business.Entities.BusinessEntity
{
...
}
public class ImportFileList : Fwk.Business.Entities.EntityList<ImportFileEntity>
{
}
}
Fwk.Business.Entities.BusinessEntity has a function named GetChanges() that using reflection iterates through all properties and checks if they changed their value (using a copy of the original BusinessEntity). It even checks if the property is itself an instance of Fwk.Business.Entities.BusinessEntity and if so recursively calls the GetChanges method. But my problem is when I have a prope开发者_JAVA技巧rty that is an instance of Fwk.Business.Entities.EntityList. I want to call each element's GetChanges method, but I can't seem to identify these EntityList<> properties. I've tried with
pi.GetValue(this, null).GetType().IsSubclassOf(typeof(EntityList<BusinessEntity>))
where pi is a PropertyInfo element that identifies the property I'm checking, but this returns false. I've also tried many other Type functions such as IsInstanceOfType and IsAssignableFrom, always getting a false where I need a true. The weird thing is that if I check for a specific BusinessEntity type it does work:
pi.GetValue(this, null).GetType().IsSubclassOf(typeof(EntityList<ImportFileEntity>))
but of course this is not acceptable since I can have a list of ANY BusinessEntity.
Can anyone help me solve this?
Than's in advance for all replys Alex.
UPDATE: SLaks gave me a good answer and I coded this:
bool isEntityList = false;
Type thisType = (pi.GetValue(this, null) ?? new object()).GetType();
while (thisType != typeof(object) && !isEntityList)
if (thisType.IsGenericType && thisType.GetGenericTypeDefinition() == typeof(EntityList<>))
isEntityList = true;
else
thisType = thisType.BaseType;
// If property is a subclass of EntityList, invoke GetChanges method.
if (isEntityList)
{
EntityList<BusinessEntity> elList = (EntityList<BusinessEntity>)pi.GetValue(this, null);
foreach (BusinessEntity beEntity in elList)
returnValue += beEntity.GetChanges(messageFormat, stopAtFirstDifference);
}
But I'm getting a cast exception when doing
EntityList<BusinessEntity> elList = (EntityList<BusinessEntity>)pi.GetValue(this, null);
Ah! I think my problem is C# 3.5 does not accept covariance (something new to me, and existent in 4.0). So I had to expose a property with the list as BusinessEntities
At EntityList where BE : BusinessEntity, new()
public virtual List<BusinessEntity> ItemsAsBE
{
get
{
List<BusinessEntity> returnValue = new List<BusinessEntity>(this.Items.Count);
foreach (BusinessEntity item in this.Items)
returnValue.Add(item);
return returnValue;
}
}
and at BusinessEntity
// If property is a subclass of EntityList, invoke GetChanges method.
if (isEntityList)
{
foreach (BusinessEntity beEntity in thisType.GetProperty("ItemsAsBE").GetValue(pi.GetValue(this, null), null) as List<BusinessEntity>)
returnValue += beEntity.GetChanges(messageFormat, stopAtFirstDifference);
}
Thanks everyone! Hope this help someone in the future!
You need to recursively loop through the Type
's base types, and look for a Type which IsGenericType
and for which GetGenericTypeDefinition() == typeof(EntityList<>)
精彩评论