【问题标题】:C# how to recursively search object for objects of type x [duplicate]C#如何递归搜索x类型的对象[重复]
【发布时间】:2020-03-28 06:44:47
【问题描述】:

我需要从一个复杂对象中检索所有 X 类型的对象。

public class Dog
{
    public string Name {get;set;}
    public int Age {get;set;}
    public Owner Owner{get;set;}
    public Kennel Kennel {get;set;}
}

public class Kennel
{
    public string Name {get;set;}
    public Address Address{get;set;}
    public List<Dog> Dogs {get;set;}
}

public class Owner
{
    public string Name {get;set;}
    public string State {get;set;}
    public Address Address{get;set;}
}

如果我有一个由 Dog 组成的对象,我需要检索所有子对象中的所有地址对象。

【问题讨论】:

  • 我在你的问题中看不到任何递归。您需要 2 个对象:所有者地址和犬舍地址
  • 抱歉,狗窝里应该有狗名单
  • 如果狗在狗窝里,他的狗窝字段是否设置为包含它的狗窝(也就是说,这个图中有没有循环?)

标签: c# recursion


【解决方案1】:

如果我理解正确,您可能需要使用 Reflection 来检索 Address 对象:

public static class MyExtensions
{
    public static List<Address> GetAddresses(this Dog dog)
    {
        var addresses = new List<Address>();
        GetAddress(dog, ref addresses);
        return addresses;
    }

    private static void GetAddress(object property, ref List<Address> addresses)
    {
        if (property == null)
        {
            return;
        }

        var props = property.GetType()
                            .GetProperties()
                            .Where(p => p.PropertyType.IsClass && 
                                       !p.PropertyType.IsPrimitive)
                            .ToList();

        foreach (var prop in props)
        {
            if (prop.PropertyType == typeof(Address))
            {
                var address = prop.GetValue(property) as Address;
                addresses?.Add(address);
            }

            var next = prop.GetValue(obj: property);

            // When property is a collection
            if (next is IEnumerable collection)
            {
                foreach (var item in collection)
                {
                    GetAddress(property: item,
                               addresses: ref addresses);
                }
            }
            else
            {
                GetAddress(property: next,
                           addresses: ref addresses);
            }
        }
    }
}

及用法示例:

var dogs = new List<Dog>();
for (int i = 0; i < 5; i++)
{
    var dog = new Dog
    {
        Name = $"Dog - {i}",
        Age = 10,
        Kennel = new Kennel
        {
            Address = new Address()
        },
        Kennels = new List<Kennel>
        {
            new Kennel
            {
                Address = new Address()
            },
            new Kennel
            {
                Address = new Address()
            },
            new Kennel()
            {
                Address = new Address()
            }
        },
        Owner = new Owner
        {
            Address = new Address(),
            Kennel = new Kennel
            {
                Address = new Address()
            }
        }
    };

    dogs.Add(dog);
}

var address = dogs.Select(dog => dog.GetAddresses());
Console.WriteLine(address.Sum(a => a.Count)); // will print 30

请注意,使用反射可能会影响应用程序的性能。

【讨论】:

  • 在您的示例中,是否可以在 dog 中考虑犬舍列表?
  • 好问题,我会检查并回复您。
  • @AnxiousdeV 我已经更新了代码以考虑收藏,请检查。
  • 谢谢,我相信 PropertyType.IsClass 将消除包含的 IEnumerable 属性
  • 当一个元素的IsClass 属性返回true 并不意味着它不能是Enumerable。最简单的原因是Enumerable也是class(IsClass属性也返回true)。
【解决方案2】:

这里不需要递归。只需多选

Kennel home = getKennel();

List<Address> AllOwnerAddresses = home.Dogs.SelectMany(d = > d.Owner.Address).ToList();

【讨论】:

    【解决方案3】:

    假设结构是一棵树

    static IEnumerable<Address> GetAddresses(Dog dog)
    { 
        yield return dog.Owner.Address;
        yield return dog.Kennel.Address;
        foreach (var addr in dog.Kennel.Dogs.SelectMany(dogC => GetAddresses(dogC)))
        {
            yield return addr;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-07-26
      • 2020-04-23
      • 2017-09-09
      • 2014-04-08
      • 1970-01-01
      • 2018-07-30
      • 1970-01-01
      • 2022-01-04
      相关资源
      最近更新 更多