Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Oh, yay, I get to show off something I recently wrote for something else! :)</p> <p>Caveat: This code is not the most efficient in the world, and it's VERY poorly commented - it was for a personal project, and I already knew how it worked - but I think it'll get you what you're after...</p> <p>The method you'd be most interested in would be <code>public static Tuple&lt;Type, IEnumerable&lt;Type&gt;&gt; GetCommonBases(Type left, Type right)</code></p> <p>The Tuple returned is &lt;common base class, (list of common interfaces)&gt;</p> <p>A quick summary: this class, when given a type, does the following:</p> <ul> <li><p>Reverse walks up the given type until it hits no more base types, pushing each into a 'working stack'</p></li> <li><p>Pops each base type off the working stack, inserting it into a tree-like structure; If the type implements any interfaces, it adds nodes for those interface types as well</p></li> <li><p>the helper method <code>GetCommonBases</code> creates one of these <code>TypeTree</code> structures for the first type, then 'merges' in the type tree for the other given type: it does so by walking down common base types until it finds a point where you have a common base type between the two types, at which point two branches of the tree are formed. It then "drills down" to each type from the root (i.e., <code>System.Object</code>), then finds the first point of deviation. The parent of this point of deviation is the Common base type. </p></li> <li><p>The interfaces part relies on the definition of <code>Interfaces</code>, which "inherits" any Interface nodes for any ancestor. The <code>GetCommonBases</code> method pulls a list of any interfaces implemented by the two passed in types and returns an intersection of these two lists - that is, a set of interfaces that both passed in types implement.</p></li> <li><p>the method then returns these two bits of information as a <code>Tuple&lt;Type, IEnumerable&lt;Type&gt;&gt;</code>, where the first item is the common base type, if any, and the second item is the intersection of common interfaces</p></li> </ul> <pre><code> public class TypeTree { private TypeTree() { Children = new List(); } public TypeTree(Type value) : this() { // Get to the basest class var typeChain = GetTypeChain(value).ToList(); Value = typeChain.First(); foreach (var type in typeChain.Skip(1)) { Add(type); } } public Type Value { get; private set; } public TypeTree Parent { get; private set; } public List Children { get; private set; } public IEnumerable Interfaces { get { var myInterfaces = Children.Where(c => c.Value.IsInterface); return Parent == null ? myInterfaces : myInterfaces.Concat(Parent.Interfaces).Distinct(); } } public TypeTree Find(Type type) { if (Value == type) return this; return Children.Select(child => child.Find(type)).FirstOrDefault(found => found != null); } public TypeTree Add(Type type) { TypeTree retVal = null; if (type.IsInterface) { if (Value.GetInterfaces().Contains(type)) { retVal = new TypeTree { Value = type, Parent = this }; Children.Add(retVal); return retVal; } } var typeChain = GetTypeChain(type); var walkTypes = from baseType in typeChain let alreadyExists = Value == baseType || Children.Any(c => c.Value == baseType) where !alreadyExists select baseType; foreach (var baseType in walkTypes) { if (baseType.BaseType == Value) { // Add this as a child of the current tree retVal = new TypeTree { Value = baseType, Parent = this }; Children.Add(retVal); } if (Value.IsAssignableFrom(baseType)) { // we can add this as a child, potentially retVal = Children.Aggregate(retVal, (current, child) => child.Add(baseType) ?? current); } // add interfaces var interfaces = baseType.GetInterfaces().Where(i => i != type); foreach (var intType in interfaces) { (retVal ?? this).Add(intType); } } return retVal; } public override string ToString() { var childTypeNames = Children.Select(c => c.ToString()).Distinct(); return string.Format("({0} {1})", Value.Name, string.Join(" ", childTypeNames)); } public static Tuple> GetCommonBases(Type left, Type right) { var tree = new TypeTree(left); tree.Add(right); var findLeft = tree.Find(left); var findRight = tree.Find(right); var commonInterfaces = findLeft.Interfaces.Select(i => i.Value) .Intersect(findRight.Interfaces.Select(i => i.Value)) .Distinct(); var leftStack = new Stack(); var temp = findLeft; while (temp != null) { leftStack.Push(temp); temp = temp.Parent; } var rightStack = new Stack(); temp = findRight; while (temp != null) { rightStack.Push(temp); temp = temp.Parent; } var zippedPaths = leftStack.Zip(rightStack, Tuple.Create); var result = zippedPaths.TakeWhile(tup => tup.Item1.Value == tup.Item2.Value).Last(); return Tuple.Create(result.Item1.Value, commonInterfaces); } private static IEnumerable GetTypeChain(Type fromType) { var typeChain = new Stack(); var temp = fromType; while (temp != null) { typeChain.Push(temp); temp = temp.BaseType; } return typeChain; } } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload