我正在尝试使用反射在对象上设置属性。这个属性是一个ICollection——如果Collection还没有被实例化,我想要完成它。我的问题是,我有问题获得iccollection
的内部类型这是我的类
public class Report(){
public virtual ICollection<Officer> OfficerCollection { get; set; }
}
我试图通过反射访问下面定义的'Officer'类
public class Officer(){
public string Name{ get; set; }
}
代码片段
Report report = new Report()
PropertyInfo propertyInfo = report.GetType().GetProperty("OfficerCollection");
object entity = propertyInfo.GetValue(report, null);
if (entity == null)
{
//How do I go about creating a new List<Officer> here?
}
试一下:
Report report = new Report();
PropertyInfo propertyInfo = report.GetType().GetProperty("Officer");
object entity = propertyInfo.GetValue(report, null);
if (entity == null)
{
Type type = propertyInfo.PropertyType.GetGenericArguments()[0];
Type listType = typeof(List<>).MakeGenericType(type);
var instance = Activator.CreateInstance(listType);
propertyInfo.SetValue(...);
}
首先你必须得到Officer
属性:
var propertyType = propertyInfo.PropertyType;
然后提取泛型类型参数:
var genericType = propertyType.GetGenericArguments()[0];
之后调用创建一个泛型列表:
var listType = typeof(List<>).MakeGenericType(genericType);
最后创建一个泛型列表的新实例:
var listInstance = Activator.CreateInstance(listType);
…玩得开心;)
编辑:有时使用反射很好,但我建议您这样做:
public class Report()
{
private ICollection<Officer> officers;
public virtual ICollection<Officer> Officer
{
get
{
if(officers == null)
officers = new List<Officer>();
return officers;
}
set { officers = value; }
}
}
忽略整个设计听起来很糟糕的问题,我将尝试回答您的问题。您可以通过Type type = ...GetProperty(...).PropertyType
找到属性的类型。如果类型是一个具体类型—而不是当前的接口—那么您可以使用System.Activator.CreateInstance(type, null)
—其中null
表示没有构造函数参数—来创建该具体类型的实例。假设你的属性类型实际上是一个接口,你不知道你是否应该创建一个列表、数组、集合或任何其他类型来满足这个类型。然后你需要使用SetValue将实例分配给属性,但当然我们不能做到这一点。
你应该利用这些信息来重新评估你的设计,不要依赖于反射,而是使用泛型参数化(看看new()
约束)和属性的延迟初始化(如果你认为这是有意义的——我们不是读心术的人)