我正在尝试使用反射初始化类(列表)中的所有属性:
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);
}
}
}
我得到例外:
没有参数,没有为此对象定义构造函数。
我很感激提示。
答案 0 :(得分:3)
一般来说,您要创建的对象类型为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>();
答案 1 :(得分:3)
如果您将属性定义为具体类型,则可以执行此操作。这实际上有效:
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>;
}
答案 2 :(得分:1)
总结我想要实现的是在下面的构造函数中调用的方法:
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));
}
}
谢谢你们的帮助。 :)
答案 3 :(得分:0)
我也有类似的需求:在为单元测试创建业务对象时,我想将所有未初始化的列表默认为新列表,这样,如果测试需要向列表中添加一些内容,则不必担心初始化它在那里。和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();