Here is an algorithm to evaluate best matching System.Type for two types in hierarhy. This is one of answers for this StackOverflow question by Ken Kin:
Evaluate the maximum possible type to fit both of types
Algorithm
- Searching for common base class (either concrete or abstract)
FindBaseClassWithmethod
- If there is no common base class, search for common implemented interface
- It's possible for one class to implement multiple interfaces, in this case return first common based interface
FindInterfaceWithmethod
Questions
GetInterfaceHierarchyimplementaion- I'm not sure that this is correct implementation in case of complex class hierarhy with many implemented interfaces
- Now all tests are passing for selected collection from BCL and my own testing hierarhy
- Are there any other flaws that I do not pay attention to?
- I had wrote this sample in LinqPad, that's why all unittests are located at
Mainmethod. Nevertheless, any improvments toTest.Assertare ok!
Full source code with unittests is available here
// provide common base class or implemented interface
public static Type FindEqualTypeWith(this Type typeLeft, Type typeRight)
{
if(typeLeft == null || typeRight == null) return null;
var commonBaseClass = typeLeft.FindBaseClassWith(typeRight) ?? typeof(object);
return commonBaseClass.Equals(typeof(object))
? typeLeft.FindInterfaceWith(typeRight)
: commonBaseClass;
}
// searching for common base class (either concrete or abstract)
public static Type FindBaseClassWith(this Type typeLeft, Type typeRight)
{
if(typeLeft == null || typeRight == null) return null;
return typeLeft
.GetClassHierarchy()
.Intersect(typeRight.GetClassHierarchy())
.FirstOrDefault(type => !type.IsInterface);
}
// searching for common implemented interface
// it's possible for one class to implement multiple interfaces,
// in this case return first common based interface
public static Type FindInterfaceWith(this Type typeLeft, Type typeRight)
{
if(typeLeft == null || typeRight == null) return null;
return typeLeft
.GetInterfaceHierarchy()
.Intersect(typeRight.GetInterfaceHierarchy())
.FirstOrDefault();
}
// iterate on interface hierarhy
public static IEnumerable<Type> GetInterfaceHierarchy(this Type type)
{
if(type.IsInterface) return new [] { type }.AsEnumerable();
return type
.GetInterfaces()
.OrderByDescending(current => current.GetInterfaces().Count())
.AsEnumerable();
}
// interate on class hierarhy
public static IEnumerable<Type> GetClassHierarchy(this Type type)
{
if(type == null) yield break;
Type typeInHierarchy = type;
do
{
yield return typeInHierarchy;
typeInHierarchy = typeInHierarchy.BaseType;
}
while(typeInHierarchy != null && !typeInHierarchy.IsInterface);
}