Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/loops/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
遍历任何属性、嵌套对象和列表C#_C#_Loops_Reflection_Nested - Fatal编程技术网

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

遍历任何属性、嵌套对象和列表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

我得到两个类型为“Shipping”(“Shipment1”和“Shipment2”)的对象,并且必须读取它们的每个值。如果Shipment1的值为NULL/empty,我想查看Shipment2的相同值,如果该值不是NULL/empty,我必须将其复制到Shipment1。 我试图通过反射遍历我的对象,但是嵌套对象“发货人”、“收货人”、“发票”让我失败了。我希望你能帮助我。 我有以下简化的班级结构:

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