【问题标题】:Given a C# Type, Get its Base Classes and Implemented Interfaces给定一个 C# 类型,获取它的基类和实现的接口
【发布时间】:2010-12-21 20:57:28
【问题描述】:

我正在使用 C# 开发游戏引擎。我正在处理的类称为CEntityRegistry,它的工作是跟踪游戏中CEntity 的许多实例。我的目标是能够查询具有给定类型的CEntityRegistry,并获得该类型的每个CEntity 的列表。

因此,我想做的是维护一张地图:

private IDictionary<Type, HashSet<CEntity>> m_TypeToEntitySet;

并因此更新注册表:

private void m_UpdateEntityList()
        {
            foreach (CEntity theEntity in m_EntitiesToRemove.dequeueAll())
            {
                foreach (HashSet<CEntity> set in m_TypeToEntitySet.Values)
                {
                    if (set.Contains(theEntity))
                        set.Remove(theEntity);
                }
            }
            foreach (CEntity theEntity in m_EntitiesToAdd.dequeueAll())
            {
                Type entityType = theEntity.GetType();
                foreach (Type baseClass in entityType.GetAllBaseClassesAndInterfaces())
                  m_TypeToEntitySet[baseClass].Add(theEntity);

            }
        }

我的问题是没有函数Type.GetAllBaseClassesAndInterfaces-我该怎么写呢?

【问题讨论】:

  • 但您肯定不希望一个类型的实例也被视为一个实例,它的子类型和接口也是如此?
  • 您是否考虑过使用 Type.IsAssignableFrom(Type) 可能比尝试映射每个 CEntity 的整个继承层次结构更简单一些?不确定您究竟打算如何使用存储库,但可能值得一看。
  • 我想知道您是否最好将精力花在问自己为什么需要这样做以及是否有不需要反思的更直接的方法上。此外,保留所有这些对象的字典(如果您不小心实现它)可以防止它们被垃圾收集并导致程序中的内存泄漏。

标签: c# reflection inheritance types


【解决方案1】:

你可以这样写一个扩展方法:

public static IEnumerable<Type> GetBaseTypes(this Type type) {
    if(type.BaseType == null) return type.GetInterfaces();

    return Enumerable.Repeat(type.BaseType, 1)
                     .Concat(type.GetInterfaces())
                     .Concat(type.GetInterfaces().SelectMany<Type, Type>(GetBaseTypes))
                     .Concat(type.BaseType.GetBaseTypes());
}

【讨论】:

【解决方案2】:

基于 SLaks 的一个更精确的答案是:

public static IEnumerable<Type> GetBaseClassesAndInterfaces(this Type type)
{
    return type.BaseType == typeof(object) 
        ? type.GetInterfaces()
        : Enumerable
            .Repeat(type.BaseType, 1)
            .Concat(type.GetInterfaces())
            .Concat(type.BaseType.GetBaseClassesAndInterfaces())
            .Distinct();
}

【讨论】:

    【解决方案3】:

    Type 有一个属性 BaseType 和一个方法 FindInterfaces。

    https://msdn.microsoft.com/en-us/library/system.type.aspx

    所以实际上,它几乎确实有Type.GetAllBaseClassesAndInterfaces,但你必须拨打两个电话而不是一个。

    【讨论】:

    • 他想通过类型层次递归(因此GetAllBaseClass es),所以没那么简单。
    • 我想我不确定他的问题是关于使用什么方法/属性,或者如何编写一个遍历继承树的函数。我假设是前者。
    • 让 CEntity 构造函数向该字典注册可能会更简单。然后您不必查询每个对象的继承树。大量使用反射通常表明您的设计有问题。
    【解决方案4】:

    这里。前面的答案有问题。 此外,这个答案不需要“不同”。价值观已经不同了。而且这个效率更高。

        public static IEnumerable<Type> GetBaseTypes(this Type type, bool bIncludeInterfaces = false)
        {
            if (type == null)
                yield break;
    
            for (var nextType = type.BaseType; nextType != null; nextType = nextType.BaseType)
                yield return nextType;
    
            if (!bIncludeInterfaces)
                yield break;
    
            foreach (var i in type.GetInterfaces())
                yield return i;
        }
    

    【讨论】:

      【解决方案5】:

      使用此代码:

      Func<Type, List<Type>> f = ty =>
      {
          var tysReturn = new List<Type>();
          if (ty.BaseType != null)
          {
              tysReturn.Add(ty.BaseType);
          }
          tysReturn.AddRange(ty.GetInterfaces());
          return tysReturn;
      };
      

      函数f 将接受一个类型并返回其基类型和接口的列表。

      希望对你有帮助。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-12-16
        • 2013-02-14
        • 2014-07-31
        • 2010-11-11
        • 2010-09-06
        • 2020-03-13
        • 2020-09-27
        相关资源
        最近更新 更多