简体   繁体   English

遍历任何属性,嵌套对象和列表C#

[英]Iterate through any Property, nested objects and Lists C#

I get 2 objects of Type "Shipment" ("Shipment1" and "Shipment2") and must read each value of them. 我得到2个类型为“ Shipment”的对象(“ Shipment1”和“ Shipment2”),并且必须读取它们的每个值。 If the value of Shipment1 is NULL/empty I want to look into the same Value of Shipment2 and if the Value is not NULL/empty I have to copy it to Shipment1. 如果Shipment1的值为NULL /空,则我想查看相同的Shipment2值;如果该值不是NULL /空,则必须将其复制到Shipment1。 I tried to iterate through my objects with Reflection but the nested Objects "Consignor", "Consignee", "Invoices" let me fail. 我尝试使用Reflection遍历对象,但是嵌套的对象“发货人”,“收货人”,“发票”让我失败了。 I hope you can help me. 我希望你能帮助我。 I have the following simplified class structure: 我有以下简化的类结构:

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; }
}

I tried it this way. 我尝试过这种方式。 It worked for the top level properties of shipment, but not for Consignor, Consignee, Invoices etc. 它适用于装运的顶级属性,但不适用于发货人,收货人,发票等。

            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
             }       
       }

I ended up with this, having shipment1 with the same values that shipment2 , even if shipment1 was null at the beginning. 我结束了这一点,具有带shipment2,即使shipment1是开头空值相同shipment1。

Please note that it copies IEnumerable like pointers. 请注意,它像指针一样复制IEnumerable。 After the copy, editing copy.Invoices will also edit source.Invoices, and vice versa. 复制后,编辑副本。发票也将编辑来源发票,反之亦然。

// 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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM