Useful LINQ Method- GetMemberTypeChain

Recently, I have been working on a custom LINQ provider in C#.  In a later post (when I have more time to write) I will go in depth into what I am worked on and what have I learned about writing a LINQ provider.  But for now I will present a simple function that simplified part of my work.  It is called GetMemberTypeChain (not as bad as it sounds).  Given a member access expression it will return the types of all parts of the member access chain.  What this means is that given some expression like "myObject.FieldA.FiledB" it will return a list containing the type of each field/property.

 

In addition to this the method also allows you to filter out compiler created types.  When you have a member access which is using a parameter from a FROM clause in a LINQ query the compiler will often createone or more anonymous type.  Then unknowlingly the object you are trying to access now has a few anonymous field accesses in front of it.  For my purposes I wanted to be able to easily just analyze the types of the relevant parts of the expression. 

 

So without further adieu ... GetMemberTypeChain:

 

    1: private List<Type> GetMemberTypeChain(Expression expression, bool ignoreCompilerGeneratedTypes)
    2: {
    3:     if (expression == null) return null;
    4:     if (expression.NodeType == ExpressionType.MemberAccess)
    5:     {
    6:         MemberExpression memberExpression = (MemberExpression)expression;
    7:         var result = GetMemberTypeChain(memberExpression.Expression, ignoreCompilerGeneratedTypes);
    8:         Type type = memberExpression.Type;
    9:         if (!(ignoreCompilerGeneratedTypes && IsCompilerGeneratedType(type)))
   10:             result.Add(type);
   11:         return result;
   12:     }
   13:     else if (expression.NodeType == ExpressionType.Constant || expression.NodeType == ExpressionType.Parameter)
   14:     {
   15:         var typeList = new List<CustomTypeInfo>();
   16:         Type type = expression.Type;
   17:         if (!(ignoreCompilerGeneratedTypes && IsCompilerGeneratedType(type)))
   18:             typeList.Add(type);
   19:         return typeList;
   20:     }
   21:     else
   22:     {
   23:         throw new NotSupportedException("Expression type not supported: " + expression.GetType().FullName);
   24:     }
   25: }
   26:  
   27: private bool IsCompilerGeneratedType(Type type)
   28: {
   29:     var compilerGenerateds = type.GetCustomAttributes(typeof(CompilerGeneratedAttribute), true);
   30:     return (compilerGenerateds != null && compilerGenerateds.Length > 0);
   31: }