0

Given a sequence of assemblies with classes eg.

  AssemblyA
    Customer
  AssemblyB
    Customer : AssemblyA.Customer
  AssemblyC
    Customer : AssemblyB.Customer

Given the name (not taken care of namespace) Customer, can I use LINQ to query against the sequence of assemblies to find the customer at the bottom of the inheritance chain (AssemblyC.Customer in this case) ?

Ani
  • 111,048
  • 26
  • 262
  • 307
Marcus
  • 1,866
  • 1
  • 20
  • 33
  • This question isn't clear. Are you trying to use LINQ to query the reflection metadata about the `Customer` classes or are you using it to query some kind of collection of `Customer` objects? – LBushkin Sep 16 '10 at 14:48
  • 1
    What if it's a branching tree? – recursive Sep 16 '10 at 14:56
  • @LBushkin: All i want is type that is at the bottom of the inheritance chain from a sequence of assemblies. A System.Type object to be precise. – Marcus Sep 16 '10 at 15:28

3 Answers3

1
IEnumerable<Assembly> assemblies = ...
Assembly assemblyA = ...

// Since you say the only fact you wish to use about the class is that it
// is named 'Customer' and it exists in Assembly A, this is just about the 
// only way to construct the Type object. Pretty awful though...
Type customerType = assemblyA.GetTypes() 
                             .Single(t => t.Name == "Customer");    

// From all the types in the chosen assemblies, find the ones that subclass 
// Customer, picking the one with the deepest inheritance heirarchy.
Type bottomCustomerType = assemblies.SelectMany(a => a.GetTypes())
                                    .Where(t => t.IsSubclassOf(customerType))
                                    .OrderByDescending(t => t.GetInheritanceDepth())
                                    .First();
 ...

public static int GetInheritanceDepth(this Type type)
{
    if (type == null)
        throw new ArgumentNullException("type");

    int depth = 0;

    // Keep walking up the inheritance tree until there are no more base classes.
    while (type != null)
    {
        type = type.BaseType;
        depth++;
    }

    return depth;
}
Ani
  • 111,048
  • 26
  • 262
  • 307
  • Nice, that works. The reason to why I asked this question was to see if someone could construct a nice LINQ-query to do this, my current solution looks alot like yours. – Marcus Sep 17 '10 at 08:51
  • Not exactly what I needed, but close. In this case, I just wanted to know if a type derived from some type in the same assembly. Your answer helped: `public static bool CanTypeCastTo(this Type derivedType, Type baseType) { if (baseType == nullType) throw new ArgumentNullException("baseType"); t =derivedType.BaseType; bool result = t == baseType; while (t != null && !result) { t = t.BaseType; result = t == baseType || t.IsSubclassOf(baseType);} return result; }` Thanks again for your answer. – fourpastmidnight Aug 30 '12 at 16:26
0

This tool might help you:

http://www.red-gate.com/products/reflector/

TimS
  • 5,922
  • 6
  • 35
  • 55
  • Well, thats not gonna help me here, I have knowledge about the structure of all assemblies, I even have the source :) – Marcus Sep 16 '10 at 15:29
0

The first question is how to determine the assemblies to be searched. System.Reflection.Assembly provides a number of methods for listing certain types of assemblies - for example GetReferencedAssemblies() will find assemblies referenced by a given assembly - useful if you have Assembly C (which refernces B and A), but not if you just have Assembly A (which references none). You could also scan the disk, or other methods, depending on your needs.

Once you've determined how to iterate assemblies, use the technique from this item to find classes that derive from the class in question: Discovering derived types using reflection

Apply this logic recursively until you reach the end of the tree. The commenter on your question is right - the tree may have multiple branches.

I do not know why you'd want to use Linq to do this - Linq does not seem built for this type of question. I have not personally found a way to do recursion or queue-based operations well inside of Linq. I'd just use C# or VB plain statements for this rather than Linq.

Community
  • 1
  • 1
Slaggg
  • 6,381
  • 7
  • 28
  • 27