有没有办法确定给定的 class 是否引用了另一个 class?

Is there a way of identifying if a given class has any references to another class?

我可以通过反射来处理层次结构,是的,但它具有挑战性,因为元素是多种多样的。所以:

class A
{
    string Hello;
}

class B
{
    List<A> Hellos;
}

class E
{
    A OtherRandomness;
}
class D:B
{
   E randomthing;
}

class C:D
{
    string OtherThing;
}

我有一个类型为 C 的对象,我希望能够找到并确定它具有 A 对象的列表,然后处理它们。

当然,现实生活中的例子比这更复杂,但原理是一样的。我已经尝试通过属性进行递归循环,但我正在努力寻找处理方法 a) 不尝试处理字符串和 int 对象和 b) 识别 属性 类似于 X 的可枚举对象。事实上可能有 classes 的可枚举值继承自 A.

如果有人能提出一种使这变得简单的方法,我们将不胜感激。我需要能够在很多地方执行此操作,因此我必须能够从任何 class 类型开始。

所以我从 x 开始。在这种情况下,x 是 C,但 x 也可以很容易地成为 Z,没有指向类型 A 的链接。

此外,这需要判断我是否有 class D。我希望能够拿起 Hellos 和 randomthing。

我假设这些是 public 实例属性。如果你想要别的东西,你可以调整 BindingFlags.

我的解决方案的想法是测试 属性 的类型是否是通用的。如果是,它会测试其中一个类型参数是否为 typeof(A)。但是,它不会测试像 List<List<A>> 这样的嵌套泛型类型。这将需要递归方法。

var props = typeof(C).GetProperties(BindingFlags.Instance | BindingFlags.Public)
    .Where(p => p.PropertyType.IsGenericType &&
                p.PropertyType.GenericTypeArguments.Any(t => t == typeof(A)));
foreach (var prop in props) {
    Console.WriteLine(prop);
}

打印:

System.Collections.Generic.List`1[MyNamespace.A] Hellos


使用此类型层次结构更具体地测试 A 的枚举:

class A
{
    public string Hello { get; set; }
}

class AA : A
{
}

class B
{
    public List<A> Hellos { get; set; }
    public List<AA> AAHellos { get; set; }
}

class D : B
{
    public A randomthing { get; set; }
}

class C : D
{
    public string OtherThing { get; set; }
}

测试:

var c = new C {
    Hellos = new List<A> {
        new A { Hello = "Hello" },
        new A { Hello = "World" }
    },
    AAHellos = new List<AA> {
        new AA { Hello = "Hello" },
        new AA { Hello = "World AA" }
    }
};
var enumerableOfA = typeof(IEnumerable<A>);
var props = c.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public)
    .Where(p => enumerableOfA.IsAssignableFrom(p.PropertyType));
foreach (var prop in props) {
    Console.WriteLine(prop);
    var list = (IEnumerable<A>)prop.GetValue(c);
    foreach (var item in list) {
        Console.WriteLine(item.Hello);
    }
}

打印:

System.Collections.Generic.List`1[MyNamespace.A] Hellos
Hello
World
System.Collections.Generic.List`1[MyNamespace.AA] AAHellos
Hello AA
World AA

这 return 的 AA 列表可能令人惊讶。这是因为接口声明中的 out 关键字 IEnumerable<out T> 使其成为协变的。

然而,这将不包括,例如Dictionary<int,A>,因为字典实现了IEnumerable<KeyValuePair<int,A>>。我的第一个解决方案是 return 这样的 属性,但是这样就需要更多的工作来获取字典条目。