【问题标题】:How can you programmatically find the deepest common base type from a bunch of subclasses?如何以编程方式从一堆子类中找到最深的公共基类型?
【发布时间】:2013-09-13 12:17:22
【问题描述】:

给定一个不同对象的集合,是否有可能找到它们共享的最具体的基类?

例如,给定具有这些类层次结构的对象...

object -> Vehicle -> WheeledVehicle -> Car -> SportsCar
object -> Vehicle -> WheeledVehicle -> Bus
object -> Vehicle -> WheeledVehicle -> MotorCycle
object -> Vehicle -> WheeledVehicle -> Tricycle -> BigWheel
object -> Vehicle -> WheeledVehicle -> Tricycle -> Green Machine

(为了好玩... http://www.wired.com/autopia/2011/03/green-machine-bike-is-a-big-wheel-for-grownups)

能不能用这个签名写一个函数...

public Type GetCommonBaseType(List<object> objects)
{
    ...
};

...让它返回“WheeledVehicle”?

我的想法是以某种方式为每个对象建立继承链列表,将它们反转,使它们都以“对象”开头,然后逐个检查所有列表中的匹配项。如果任何项目不匹配,那么前面的步骤是您最深匹配的基类型。

但是,由于“base”是内部成员,因此我不确定如何建立链。这是您可以使用反射来确定的吗?

【问题讨论】:

标签: c# inheritance reflection subclass


【解决方案1】:

您可以使用反射来执行此操作。假设我们从 Type 实例而不是对象开始——这更通用,您可以简单地将对象列表转换为它们的运行时类型列表,以涵盖您提到的用例。

这个想法是遍历每个输入类型的所有基类,并为每个基类增加一个“类型实例计数器”。完成此操作后,输入类型的所有公共基础的计数器必然等于输入类型的数量。其中哪一个是最衍生的?很简单,选择 任何 输入类型并开始遍历其类型层次结构,直到找到其中一个公共基础;该类型是派生最多的公共基础。

代码

我将使用这个扩展方法:

public static IEnumerable<Type> TypeHierarchy(this Type type)
{
    do
    {
        yield return type;
        type = type.BaseType;
    } while (type != null);
}

然后允许这个实现——多亏了 LINQ,它读起来几乎像英语:

public Type MostDerivedCommonBase(IEnumerable<Type> types)
{
    if (!types.Any()) return null;

    var counts = new Dictionary<Type, int>();
    var total = types.Count();
    foreach(var type in types.SelectMany(t => t.TypeHierarchy()))
    {
        if (!counts.ContainsKey(type))
        {
            counts[type] = 1;
        }
        else
        {
            counts[type]++;
        }
    }

    return types.First().TypeHierarchy().First(t => counts[t] == total);
}

你可以很容易地练习这个,例如

var types = new[] { typeof(MemoryStream), typeof(FileStream) };
Console.WriteLine(MostDerivedCommonBase(types)); // System.IO.Stream

更新

事后看来,显然也可以完全使用 LINQ 来构建类型字典。因此,如果紧凑是您的一杯茶,代码可以简化为:

public Type MostDerivedCommonBase(IEnumerable<Type> types)
{
    if (!types.Any()) return null;

    var counts = types.SelectMany(t => t.TypeHierarchy())
                      .GroupBy(t => t)
                      .ToDictionary(g => g.Key, g => g.Count());

    var total = counts[typeof(object)]; // optimization instead of types.Count()
    return types.First().TypeHierarchy().First(t => counts[t] == total);
}

【讨论】:

  • 我是反对票。不过,我将其更改为赞成票。我投了反对票,因为您的解决方案中没有代码,并且考虑到编写代码并不是很简单,我觉得任何不包括工作代码的答案都是无用的。
  • @evanmcdonnal:我觉得不值得反对,因为代码很短并且完全遵循散文中描述的算法。但无论如何不用担心。
  • 这可能是正确的,但我确信如果不通过一些示例来理解它,对于许多程序员来说将是一种延伸。我并没有完全理解它,并计划采取一种非常不同的方法。递归检索父对象,当集合中的每个类型都相同时返回,或者当父类型变为 null 时抛出。
  • @evanmcdonnal:你说得有道理,我编辑以收紧描述(主要始终使用“输入类型”)。里面有很多“类型”,但不是很清楚。
猜你喜欢
  • 2012-10-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-11
  • 1970-01-01
  • 2020-02-05
  • 1970-01-01
相关资源
最近更新 更多