There’s IsAssignableFrom method returns a boolean value indicates if one type is assignable from another type.
How can we not only test if they are assignable from or to each other, but also know the minimum covariant type for best fit?
Consider the following example(C# 4.0)
-
Code
// method body of Func is irrelevant, use default() instead Func<char[]> x = default(Func<char[]>); Func<int[]> y = default(Func<int[]>); Func<Array> f = default(Func<Array>); Func<IList> g = default(Func<IList>); g=x; g=y; y=x; // won't compile x=y; // won't compile // following two are okay; Array is the type for the covariance f=x; // Array > char[] -> Func<Array> > Func<char[]> f=y; // Array > int[] -> Func<Array> > Func<int[]> // following two are okay; IList is the interface for the covariance g=x; g=y;
In the example above, what to find is the type between char[] and int[].
update:
It turns out
FindInterfaceWithcan be simplified and to build a flatten type hierarchy becomes redundant as the base classes are not necessarily involved, as long as we take the type itself into account when it is an interface; so I’ve added an extension methodGetInterfaces(bool). Since we can sort the interaces by the rules of coverage, the sorted intersection of interfaces are the candidates. If all of them are equally good, I said none of them is considered the best one. If it’s not the case, then the best one must cover one of the others; and because they are sorted, this kind of relationship should exists in the right most two interfaces in the array to denote that there is a best interface in common which is the most specific.The code can be simplified by using
Linq; but in my scenario, I should reduce the requirement of references and namespaces as possible ..Code
There’re two recursive methods; one is
FindInterfaceWith, the other is an important methodGetTypesArrayas there is already a method namedGetTypeArrayof classTypewith a different of usage.It works like the method Akim provided GetClassHierarchy; but in this version, it builds an array like:
output of hierarchy
As we are aware of they are in a particular order, which is how it makes things work. The array
GetTypesArraybuilt is in fact a flatten tree. The array is actually in the model as the following:diagram
The interfaces in the returning array is sorted by
Array.Sortwith the ordering rules provided by theGetCoverageComparison.There are some things to mention, for example, the possibility of multiple interfaces implementation been mentioned not only once in some answers(like [this]); and I have defined the way to solve them, those are:
note
The GetInterfaces method does not return interfaces in a particular order, such as alphabetical or declaration order. Your code must not depend on the order in which interfaces are returned, because that order varies.
Because of recursion, the base classes are always ordered.
If two interfaces have the same coverage, neither of them will be considered eligible.
Suppose we have these interfaces defined(or classes are just fine):
then which one is better for assignment of
IAlphaandIBravo? In this case,FindInterfaceWithjust returnsnull.In the question [ How to find the smallest assignable type in two types (duplicate)? ], I stated:
a wrong deduction
However, now we can look at the method
FindAssignableWith, it has to call other two methods is based on the original assumption, The paradoxical bug just disappeared magically.About coverage comparison rule of ordering interfaces, in the delegate
GetCoverageComparison, I use:dual rules
compare two interfaces in a source interfaces array, with each covering how many others in the source, by calling
CountOverlappedIf rule 1 does not distinguish them (returns
0), the secondary ordering is to callCountOccurrenceto determine which has been inherited more times by others and then comparingthe two rules are equivalent to the
Linqquery:FindInterfaceWithwill then perform the possibly recursive call, to figure out is this interface sufficient to recognized as the most common interface or just another relation likeIAlphaandIBravo.And about the method
FindBaseClassWith, what it returns is different from the original assumption of if any parameter is null then it returns null. It actually returns another argument passed in.This is related to the question [ What should the method `FindBaseClassWith` return? ] about method chaining of
FindBaseClassWith. In the current implementation, we can call it like:method chaining
It will return
typeof(Array); thank to this feature, we can even callWhat we may not able to do with my implementation is to call
FindInterfaceWithlike above, because of the possibility of relations likeIAlphaandIBravo.I’ve had the code tested in some situations by calling
FindAssignableWithas the examples shown:output of assignable types
The
List'1test appearsIListis because I testedtypeof(List<int>)withtypeof(List<String>); and theDictionary'2are bothDictionary<String, String>. Sorry that I did not do the work to present the exact type names.