比较对象并确定常见类型

时间:2013-04-29 15:47:18

标签: c# .net inheritance types

简短版本:代码中的注释是否正确?我认为它们是不正确的,应该颠倒过来。

public Type GetTestClass(Object left, Object right)
{
    if (left == null || right == null) return null;

    Type leftClass = left.GetType();
    Type rightClass = right.GetType();
    Type testClass;
    if (leftClass.IsInstanceOfType(right))
    {
        testClass = leftClass;
        if (!rightClass.IsInstanceOfType(left))
        {
            // rightClass is a subclass of leftClass
            testClass = rightClass;
        }
    }
    else if (rightClass.IsInstanceOfType(left))
    {
        testClass = rightClass;
        if (!leftClass.IsInstanceOfType(right))
        {
            // leftClass is a subclass of rightClass
            testClass = leftClass;
        }
    }
    else
    {
        // The two classes are not related.
        testClass = null;
    }

return testClass;
}

我在我正在处理的代码库中遇到了这段代码,我认为这些注释不正确。我认为评论//rightClass is a subclass of leftClass//leftClass is a subclass of rightClass不正确。例如,如果leftClass的类型为ObjectrightClass的类型为MyClass(继承自Object),那么这就是我相信代码的工作方式......

  1. ObjectMyClass的实例,为FALSE
  2. MyClassObject的实例为TRUE
  3. testClass设置为MyClass
  4. NOT(ObjectMyClass的实例为FALSE)为TRUE
  5. testClass设置为Object
  6. 返回
  7. testClass == Object
  8. 我相信这是正确的功能......最终代码试图返回两个类的最超级类(也可以说是公共Base类),如果它们不相关则返回null。使用上面的例子(步骤1-5),实际上说leftClass是一个SUPC类的rightClass是不正确的...或者,反之,rightClass是一个leftClass的SUBCLASS?

2 个答案:

答案 0 :(得分:1)

leftClass.IsInstanceOfType(right)表示“右边是左边”。 rightClass.IsInstanceOfType(left)表示“左边是右边”。

如果右边是左边,但左边不是右边,那么左边必须是超类,右边必须是子类。这相当于第一种情况,你有注释“rightClass是leftClass的子类”。因此,评论的意图似乎是准确的。

但是,我发现该方法存在一些问题。评论是你最不担心的。

  1. 如果任一参数为null,它将抛出NullReferenceException

  2. 它会对GetType()进行不必要的调用,因为IsInstanceOfType的实际源代码如下所示:

    public virtual bool IsInstanceOfType(object o)
    {
        if (o == null)
        {
            return false;
        }
        return this.IsAssignableFrom(o.GetType());
    }
    

    您应该使用@ p.s.w.g.的建议并使用IsAssignableFrom,并且可能考虑重构签名比较两个类型而不是两个对象。

  3. 任何两种具体类型始终至少具有System.Object的公共基本类型。在这里返回null是不可接受的结果。

  4. 它不处理一种类型不是从另一种类型线性派生的情况,但两者仍然具有比System.Object更多派生的公共基类。例如,

    public class Base { }
    
    public class A : Base { }
    
    public class B : Base { }
    

    您的方法会说AB不相关并返回null,其中正确的“公共基数”为Base

  5. 我会看一下Easiest way to get a common base class from a collection of types提供的实现,这仍然不完美,但比你发布的更好。

    更新:工作代码

    我决定不要吝啬,我已经发布了我在下面用于此目的的方法。祝你好运。

        /// <summary> Finds the most derived common base class of all the provided types, or System.Object if there is no common base class  </summary>
        public static Type CommonBaseClass(params Type[] types)
        {
            if(ReferenceEquals(types,null)) return typeof(object);
            types = types.Where(x => !ReferenceEquals(x,null)).Distinct().ToArray();
            switch (types.Length)
            {
                case 0: return typeof(object);
                case 1: return types[0].IsInterface ? typeof(object): types[0];
                default:
                    IEnumerable<IEnumerable<Type>> hierarchies = types.Select(ClassHierarchy).OrderBy(x => x.Count());
                    Queue<Type> smallest = new Queue<Type>(hierarchies.First().Reverse());
                    hierarchies = hierarchies.Skip(1);
                    do
                    {
                        int maxPossible = smallest.Count;
                        hierarchies = hierarchies.Select(each => each.Take(maxPossible));
                        Type candidate = smallest.Dequeue();
                        if (hierarchies.All(each => each.Last() == candidate))
                            return candidate;
                    } while (smallest.Count > 1);
                    return typeof(object);
            }
        }
    
    
        ///<summary>Gets the class hierarchy of the provided type, in order of derivation, e.g. : (System.Object,CustomBaseType,CustomConcreteType,...), or the singleton of System.Object type if the provided type is an interface or null </summary>
        public static IEnumerable<Type> ClassHierarchy(this Type type)
        {
            if (type == null || type.IsInterface) type = typeof(object);
            var stack = new Stack<Type>();
            do
            {
                stack.Push(type);
                type = type.BaseType;
            } while (type != null);
            return stack;
    
        }
    

答案 1 :(得分:0)

编辑:更新以反映处理界面类型的更改 编辑:添加额外功能以支持超过2种类型。

首先:一个类型不能是另一个类型的实例(除非我们讨论类型Type的实例。)只有一个对象可以是一个类型的实例。

类型可以是彼此的子类型(使用IsSubType)。类型可以分配给另一种类型(使用IsAssignableFrom)。

要查找常见类型,请尝试此示例。这将始终产生一个公共类型(对象):

    /// <summary>
    /// Returns the most common type of two types.
    /// If no common type can be found, null is returned.
    /// </summary>
    static public Type GetCommonBaseClass(Type a, Type b)
    {
        if ((a == null) || (b ==null))
            return null;
        if (a.IsInterface || b.IsInterface)
            return null;
        if (a.IsAssignableFrom(b))
            return a;
        while (true)
        {
            if (b.IsAssignableFrom(a))
                return b;
            b = b.BaseType;
        }
    }

    /// <summary>
    /// Returns the most common type of one or more types.
    /// If no common type can be found, null is returned.
    /// </summary>
    static public Type GetCommonBaseClass(params Type[] types)
    {
        if ((types == null) || (types.Length == 0))
            return null;
        Type type = types[0];
        for (int i = 0; i < types.Length; i++)
            type = GetCommonBaseClass(type, types[i]);
        return type;
    }

从您的函数调用:

public Type GetTestClass(Object left, Object right)
{
     return GetCommonBaseClass(left.GetType(), right.GetType());
}