我正在尝试使用反射初始化类(列表(中的所有属性:
public class EntitiesContainer
{
public IEnumerable<Address> Addresses { get; set; }
public IEnumerable<Person> People { get; set; }
public IEnumerable<Contract> Contracts { get; set; }
public EntitiesContainer()
{
var propertyInfo = this.GetType().GetProperties();
foreach (var property in propertyInfo)
{
property.SetValue(property, Activator.CreateInstance(property.GetType()), null);
}
}
}
我收到异常:
没有为没有参数的此对象定义任何构造函数。
我将不胜感激提示。
只要将属性定义为具体类型,就可以执行此操作。这实际上有效:
public class EntitiesContainer
{
public List<Address> Addresses { get; set; }
public List<Person> People { get; set; }
public List<Contract> Contracts { get; set; }
public EntitiesContainer()
{
var propertyInfo = this.GetType().GetProperties();
foreach (var property in propertyInfo)
{
property.SetValue(this, Activator.CreateInstance(property.PropertyType));
}
}
}
不能创建IEnumerable<T>
的实例,因为它是一个接口。
但是你为什么要这样做呢?最好使用 C#6 中引入的自动属性初始值设定项初始化属性:
public class EntitiesContainer
{
public IEnumerable<Address> Addresses { get; set; } = new List<Address>;
public IEnumerable<Person> People { get; set; } = new List<Address>;
public IEnumerable<Contract> Contracts { get; set; } = new List<Address>;
}
一般来说,这里要创建的对象类型是property.PropertyType
;而要设置值的对象是 this
,所以:
property.SetValue(this, Activator.CreateInstance(property.PropertyType), null);
但是!你的属性是IEnumerable<T>
的,而不是List<T>
的——不能创建一个接口,只能创建一个具体的类型。所以你必须做很多工作来解构泛型IEnumerable<Foo>
Foo
(var args = type.GetGenericTypeArguments()
(和构造一个List<Foo>
(typeof(List<>).MakeGenericType(args)
(。或者只是将属性类型更改为List<T>
!
坦率地说,这样做会更容易:
public IEnumerable<Address> Addresses { get; set; } = new List<Address>();
public IEnumerable<Person> People { get; set; } = new List<Person>();
public IEnumerable<Contract> Contracts { get; set; } = new List<Contract>();
或:
public List<Address> Addresses { get; } = new List<Address>();
public List<Person> People { get; } = new List<Person>();
public List<Contract> Contracts { get; } = new List<Contract>();
总结一下,我想实现的是构造函数中调用的方法,如下所示:
private void InitializeAllCollections()
{
var properties = this.GetType().GetProperties();
foreach (var property in properties)
{
var genericType = property.PropertyType.GetGenericArguments();
var creatingCollectionType = typeof(List<>).MakeGenericType(genericType);
property.SetValue(this, Activator.CreateInstance(creatingCollectionType));
}
}
谢谢大家的帮助。 :)
我也有类似的需求:在为单元测试创建业务对象时,我想将所有未初始化的列表默认为新列表,这样如果测试需要向列表中添加某些内容,我就不必担心在那里初始化它。 与 OP 一样,我有太多的业务对象无法将它们全部更改为默认值。 我的解决方案是其他解决方案的混合;例外情况是我只想要 List 属性,并且仅当它们尚未初始化时:
public static T DefaultLists<T>(this T obj)
{
var properties = obj.GetType().GetProperties().Where(q => q.PropertyType.Name == "List`1" && q.GetValue(obj) == null);
foreach(var property in properties)
property.SetValue(obj, Activator.CreateInstance(property.PropertyType));
return obj;
}
现在,我的示例对象创建者可以返回新的 businessObject.DefaultLists((;