遍历任何属性、嵌套对象和列表C#
我得到两个类型为“Shipping”(“Shipment1”和“Shipment2”)的对象,并且必须读取它们的每个值。如果Shipment1的值为NULL/empty,我想查看Shipment2的相同值,如果该值不是NULL/empty,我必须将其复制到Shipment1。 我试图通过反射遍历我的对象,但是嵌套对象“发货人”、“收货人”、“发票”让我失败了。我希望你能帮助我。 我有以下简化的班级结构:遍历任何属性、嵌套对象和列表C#,c#,loops,reflection,nested,C#,Loops,Reflection,Nested,我得到两个类型为“Shipping”(“Shipment1”和“Shipment2”)的对象,并且必须读取它们的每个值。如果Shipment1的值为NULL/empty,我想查看Shipment2的相同值,如果该值不是NULL/empty,我必须将其复制到Shipment1。 我试图通过反射遍历我的对象,但是嵌套对象“发货人”、“收货人”、“发票”让我失败了。我希望你能帮助我。 我有以下简化的班级结构: public class Shipment { public int Id { ge
public class Shipment
{
public int Id { get; set; }
public Address Consignor { get; set; }
public Address Consignee { get; set; }
public IEnumerable<Invoice> Invoices{ get; set; }
}
public class Address
{
public string Name { get; set; }
public string Street{ get; set; }
public string Zip { get; set; }
public string City{ get; set; }
public string Country{ get; set; }
}
public class Invoice
{
public IEnumerable<Item> Items{ get; set; }
}
public class Item
{
public string Description{ get; set; }
public int Amount { get; set; }
}
最后,我得到了shipment1与shipment2具有相同的值,即使shipment1在开始时为null 请注意,它像指针一样复制IEnumerable。复制后,编辑副本。发票也将编辑源。发票,反之亦然。
// used for my test:
Shipment shipment1 = null;
Shipment shipment2 = new Shipment { Id = 42, Consignor = new Address { Name = "Foo1", Street = "Bar1", Zip = "Baz1", City = "Qux1", Country = "Quux1" }, Consignee = new Address { Name = "Foo2", Street = "Bar2", Zip = "Baz2", City = "Qux2", Country = "Quux2" }, Invoices = new Invoice[] { new Invoice { Items = new Item[] { new Item { Description = "FooBar1", Amount = 1 }, new Item { Description = "BazQux1", Amount = 1 } } }, new Invoice { Items = new Item[] { new Item { Description = "FooBar2", Amount = 2 }, new Item { Description = "BazQux2", Amount = 2 } } } } };
// kind of ugly but I didn't manage to do it prettier:
shipment1 = Work(shipment2, shipment1);
private T Work<T>(T source, T copy)
{
if (source == null)
return copy;
if (copy == null)
copy = Activator.CreateInstance<T>();
foreach (PropertyInfo prop in typeof(T).GetProperties())
{
switch (prop.PropertyType.Name.ToLower())
{
case "string":
string str = (string)prop.GetValue(source);
if (!string.IsNullOrEmpty(str))
if (string.IsNullOrEmpty((string)prop.GetValue(copy)))
prop.SetValue(copy, str);
break;
case "int32":
int i = (int)prop.GetValue(source);
if (i != 0)
if ((int)prop.GetValue(copy) == 0)
prop.SetValue(copy, i);
break;
case "address":
prop.SetValue(copy, Work(prop.GetValue(source) as Address, prop.GetValue(copy) as Address));
break;
case "ienumerable`1":
switch (prop.PropertyType.GetGenericArguments()[0].Name.ToLower())
{
case "invoice":
IEnumerable<Invoice> invoices = (IEnumerable<Invoice>)prop.GetValue(source);
if (invoices != null && invoices.Count() > 0)
if ((IEnumerable<Invoice>)prop.GetValue(copy) == null)
prop.SetValue(copy, invoices);
break;
// edit: this is actually useless
/*
case "item":
IEnumerable<Item> items = (IEnumerable<Item>)prop.GetValue(source);
if (items != null && items.Count() > 0)
if ((IEnumerable<Item>)prop.GetValue(copy) == null)
prop.SetValue(copy, items);
break;
*/
}
break;
}
}
return copy;
}
//用于我的测试:
shipment1=空;
发货发货人2=新发货{Id=42,发货人=新地址{Name=“Foo1”,Street=“Bar1”,Zip=“Baz1”,City=“Qux1”,Country=“Quux1”},收货人=新地址{Name=“Foo2”,Street=“Bar2”,Zip=“Baz2”,City=“Qux2”,Country=“Qux2”},发票=新发票{新发票{项目=新项目{说明=“FooBar1”,金额=1},新项目{Description=“bazzux1”,金额=1}},新发票{Items=newitem[]{newitem{Description=“FooBar2”,金额=2},新项目{Description=“bazzux2”,金额=2}};
//有点难看,但我没能做得更漂亮:
shipment1=工作(shipment2,shipment1);
私人T工作(T来源,T副本)
{
if(source==null)
返回副本;
if(copy==null)
copy=Activator.CreateInstance();
foreach(typeof(T).GetProperties()中的PropertyInfo属性)
{
开关(prop.PropertyType.Name.ToLower())
{
大小写“字符串”:
string str=(string)prop.GetValue(source);
如果(!string.IsNullOrEmpty(str))
if(string.IsNullOrEmpty((string)prop.GetValue(copy)))
属性设置值(复制,str);
打破
案例“int32”:
inti=(int)prop.GetValue(源);
如果(i!=0)
如果((int)prop.GetValue(copy)==0)
属性设置值(副本,i);
打破
案例“地址”:
prop.SetValue(复制,工作(prop.GetValue(源)作为地址,prop.GetValue(复制)作为地址));
打破
案例“ienumerable`1”:
开关(prop.PropertyType.GetGenericArguments()[0].Name.ToLower())
{
案例“发票”:
IEnumerable发票=(IEnumerable)prop.GetValue(来源);
如果(发票!=null&&invoices.Count()>0)
if((IEnumerable)prop.GetValue(copy)==null)
道具设定值(副本、发票);
打破
//编辑:这实际上是无用的
/*
案例“项目”:
IEnumerable items=(IEnumerable)prop.GetValue(source);
if(items!=null&&items.Count()>0)
if((IEnumerable)prop.GetValue(copy)==null)
道具设定值(副本、项目);
打破
*/
}
打破
}
}
返回副本;
}
当shipment1
有一个地址有一个值为Zipe
,但没有值为Street
,并且shipment2
有一个地址有一个值为Street
,而Zipe
有一个不同的值时,你决定怎么办?盲目复制它?我认为地址不会在这种情况下,ld有任何意义。是的,你是对的,这没有意义。在我的用例中,address属性不会为空。这只是一个简化的类结构,我正在寻找一个迭代每个属性、嵌套对象等的算法。要循环遍历属性的代码在哪里?我添加了我的迭代示例
// used for my test:
Shipment shipment1 = null;
Shipment shipment2 = new Shipment { Id = 42, Consignor = new Address { Name = "Foo1", Street = "Bar1", Zip = "Baz1", City = "Qux1", Country = "Quux1" }, Consignee = new Address { Name = "Foo2", Street = "Bar2", Zip = "Baz2", City = "Qux2", Country = "Quux2" }, Invoices = new Invoice[] { new Invoice { Items = new Item[] { new Item { Description = "FooBar1", Amount = 1 }, new Item { Description = "BazQux1", Amount = 1 } } }, new Invoice { Items = new Item[] { new Item { Description = "FooBar2", Amount = 2 }, new Item { Description = "BazQux2", Amount = 2 } } } } };
// kind of ugly but I didn't manage to do it prettier:
shipment1 = Work(shipment2, shipment1);
private T Work<T>(T source, T copy)
{
if (source == null)
return copy;
if (copy == null)
copy = Activator.CreateInstance<T>();
foreach (PropertyInfo prop in typeof(T).GetProperties())
{
switch (prop.PropertyType.Name.ToLower())
{
case "string":
string str = (string)prop.GetValue(source);
if (!string.IsNullOrEmpty(str))
if (string.IsNullOrEmpty((string)prop.GetValue(copy)))
prop.SetValue(copy, str);
break;
case "int32":
int i = (int)prop.GetValue(source);
if (i != 0)
if ((int)prop.GetValue(copy) == 0)
prop.SetValue(copy, i);
break;
case "address":
prop.SetValue(copy, Work(prop.GetValue(source) as Address, prop.GetValue(copy) as Address));
break;
case "ienumerable`1":
switch (prop.PropertyType.GetGenericArguments()[0].Name.ToLower())
{
case "invoice":
IEnumerable<Invoice> invoices = (IEnumerable<Invoice>)prop.GetValue(source);
if (invoices != null && invoices.Count() > 0)
if ((IEnumerable<Invoice>)prop.GetValue(copy) == null)
prop.SetValue(copy, invoices);
break;
// edit: this is actually useless
/*
case "item":
IEnumerable<Item> items = (IEnumerable<Item>)prop.GetValue(source);
if (items != null && items.Count() > 0)
if ((IEnumerable<Item>)prop.GetValue(copy) == null)
prop.SetValue(copy, items);
break;
*/
}
break;
}
}
return copy;
}