GetCommonBaseClass: Readabiliy and Functionality I have two pieces of they which do almost the same thing. They both return the most common base class of two types. They differ in two aspect:


If one of the arguments is null, code A returns null and code B returns object.
If one of the arguments is an interface type, code A returns null and code B returns object.


My two questions for you:


Which code is more readable?
When it comes down to those differences, should the code:

a. return null.
b. return object.
c. throw an exception?


Code A:

    /// &lt;summary&gt;
    /// Returns the most common type of two types.
    /// If no common type can be found, null is returned.
    /// &lt;/summary&gt;
    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;
        }
    }

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


Code B:

    /// &lt;summary&gt; Finds the most derived common base class of all the provided types, or System.Object if there is no common base class  &lt;/summary&gt;
    public static Type CommonBaseClass(params Type[] types)
    {
        if(ReferenceEquals(types,null)) return typeof(object);
        types = types.Where(x =&gt; !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&lt;IEnumerable&lt;Type&gt;&gt; hierarchies = types.Select(ClassHierarchy).OrderBy(x =&gt; x.Count());
                Queue&lt;Type&gt; smallest = new Queue&lt;Type&gt;(hierarchies.First().Reverse());
                hierarchies = hierarchies.Skip(1);
                do
                {
                    int maxPossible = smallest.Count;
                    hierarchies = hierarchies.Select(each =&gt; each.Take(maxPossible));
                    Type candidate = smallest.Dequeue();
                    if (hierarchies.All(each =&gt; each.Last() == candidate))
                        return candidate;
                } while (smallest.Count &gt; 1);
                return typeof(object);
        }
    }


    ///&lt;summary&gt;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 &lt;/summary&gt;
    public static IEnumerable&lt;Type&gt; ClassHierarchy(this Type type)
    {
        if (type == null || type.IsInterface) type = typeof(object);
        var stack = new Stack&lt;Type&gt;();
        do
        {
            stack.Push(type);
            type = type.BaseType;
        } while (type != null);
        return stack;

    }
I think that code A is quite a lot simpler, so it's also more readable. It's quite clear what GetCommonBaseClass(Type a, Type b) is supposed to do and GetCommonBaseClass(params Type[] types) is also quite straightforward.
On the other hand, CommonBaseClass(params Type[] types) in Code B is much more complicated, it's hard to see what's actually going on in all that code.

Also, in code A, GetCommonBaseClass(params Type[] types) could be simplified even more by using something like types.Aggregate(GetCommonBaseClass).

Regarding the edge cases, I think that, null inputs should cause an ArgumentNullException to be thrown. (Or not, if null is really a valid value.) With interfaces, I think the correct behavior depends on your requirements. If you don't know, I think the safest choice is to throw an exception. It's trivial to allow interfaces later on, if that's needed. On the other hand, adding a restriction could cause a issues with older code that uses your method.