c# - 遍历任何属性、嵌套对象和列表 C#
问题描述
我得到 2 个类型为“Shipment”的对象(“Shipment1”和“Shipment2”),并且必须读取它们的每个值。如果 Shipment1 的值为 NULL/空,我想查看 Shipment2 的相同值,如果值不是 NULL/空,我必须将其复制到 Shipment1。我试图用反射遍历我的对象,但是嵌套的对象“Consignor”、“Consignee”、“Invoices”让我失败了。我希望你能帮助我。我有以下简化的类结构:
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; }
}
我试过这样。它适用于货运的顶级属性,但不适用于发货人、收货人、发票等。
foreach (PropertyInfo info1 in shipment1.GetType().GetProperties())
{
var datatype = info1.PropertyType;
switch (datatype.Name.ToLower())
{
case "string":
if (!string.IsNullOrEmpty((string)info1.GetValue(shipment1)))
{
string value= (string)info1.GetValue(shipment1);
string name = info1.Name;
Type type = input.GetType();
PropertyInfo info2 = shipment2.GetType().GetProperty(name);
if (string.IsNullOrEmpty((string)info2.GetValue(shipment2)))
{
info2.SetValue(shipment2, value, null);
}
}
break;
case "integer":
// and so on
}
}
解决方案
我最终得到了这个,让shipping1具有与shipping2相同的值,即使shipping1在开始时为空。
请注意,它像指针一样复制 IEnumerable。复制后,编辑 copy.Invoices 也会编辑 source.Invoices,反之亦然。
// 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;
}
推荐阅读
- amazon-web-services - 如何为 S3 存储桶中的特定嵌套文件夹创建公共策略?
- c - 节点始终插入 GLib 树的第一个节点
- swift - 快速查找系统字体中的 unicode 字符以在按钮中设置属性标题
- java - 如何将 ItemListener 注册到 CompositeItemProcessor
- javascript - ES6:如何解开内部数组并展平 JSON 数组?
- reactjs - 特定子组件的 PropTypes
- php - wp_mail() 不适用于 WordPress 插件
- serial-port - 通过 bash 脚本发送 AT 命令
- opencms - 如何使我的网站(来自自定义模板)可见?prod 服务器中仅显示默认演示站点
- python - NetworkX 中图形中的平行/重复边数