linqllblgenpro

LLBLGen TypedConstantExpression can't be converted to SetExpression


We were experiencing issues with using over 2100 elements in a contains LINQ expression, so I have rewritten the query to insert the values previously used in the contains comparison into an IEnumerable of structs of type EnquiryID exposing a simple int value (ID) and joined on this:

IEnumerable<EnquiryID> enqIdList = ListToEnquiryIdList(enquiryIDs).ToList();

var extras = (from q in lmd.Quote
join qe in lmd.QuoteExtra on q.Id equals qe.QuoteId
join ei in enqIdList on q.EnquiryId  equals ei.Id 
orderby qe.Created
select new
{
  EnquiryID = q.EnquiryId, qe.Created
}).ToArray();

This generates this exception:

"Unable to cast object of type 'System.Linq.Expressions.TypedConstantExpression' to type 'SD.LLBLGen.Pro.LinqSupportClasses.ExpressionClasses.SetExpression'.", which is clearly LLBLGEN specific

Anyone have any ideas?


Solution

  • You can access the 'Value' property of the TypedConstantExpression like so:
    (expression.Body as MethodCallExpression).Object.GetType().GetProperty("Value").GetMethod.Invoke((expression.Body as MethodCallExpression).Object, null)

    Where the expression is given by a LambdaExpression ()=>(null).GetType()

    A Complete example

    static readonly Type TypedConstantExpressionType = Type.GetType("System.Linq.Expressions.TypedConstantExpression, System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
    
            static readonly PropertyInfo TypedConstantExpressionValueProperty;
    
            [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.Synchronized | System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
            static SymbolExtensions()
            {
                TypedConstantExpressionValueProperty = IntrospectionExtensions.GetTypeInfo(TypedConstantExpressionType).GetProperty("Value");
            }
    
            /// <summary>
            /// Given a lambda expression that expressed a new object, returns the <see cref="System.Reflection.TypeInfo"/> of what type was expected to be allocated
            /// </summary>
            /// <param name="expression"></param>
            /// <returns></returns>
            public static TypeInfo GetTypeInfo(Expression<Action> expression) //Expression<Action> allows the syntax () => where Expression would require a Delgate.
            {
                Expression body = expression.Body;
    
                if (body is NewExpression)
                {
                    NewExpression newExpression = expression.Body as NewExpression;
    
                    return IntrospectionExtensions.GetTypeInfo((expression.Body as NewExpression).Constructor.DeclaringType);
                }
                else if (body is MemberExpression)
                {
                    MemberExpression memberExpression = body as MemberExpression;
    
                    return IntrospectionExtensions.GetTypeInfo(memberExpression.Member.DeclaringType);
                }
                else if (body is MethodCallExpression)
                {
                    MethodCallExpression methodCallExpression = expression.Body as MethodCallExpression;
    
                    if (methodCallExpression.Object is MemberExpression)
                    {
                        return IntrospectionExtensions.GetTypeInfo((methodCallExpression.Object as MemberExpression).Member.DeclaringType);
                    }
    
                    //Actually a RuntimeType from a TypedConstantExpression...
                    return IntrospectionExtensions.GetTypeInfo((Type)TypedConstantExpressionValueProperty.GetMethod.Invoke(methodCallExpression.Object, null));
                }
    
                throw new System.NotSupportedException("Please create an issue for your use case.");
            }
    

    Tested with the following class and code:

    public class MyTestClass
            {
                string m_Test;
    
                public string Test
                {
                    get { return m_Test; }
                    set { m_Test = value; }
                }
            }
    
            public class MyTestClass<T> : MyTestClass
            {
                T Backing;
    
                public T Property
                {
                    [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
                    get { return Backing; }
                    [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
                    set { Backing = value; }
                }
    
                public T AnotherProperty
                {
                    get;
                    set;
                }
            }
    
    
    
    System.Reflection.TypeInfo typeInfo = Media.Common.Extensions.ExpressionExtensions.SymbolExtensions.GetTypeInfo(() => new MyTestClass<int>());
    
                if (typeInfo.GetGenericArguments()[0] != typeof(int)) throw new System.Exception("Not correct type");
    
                System.Console.WriteLine("TypeInfo.Name" + typeInfo.Name);
    
                System.Console.WriteLine("TypeInfo.MetadataToken" + typeInfo.MetadataToken);
    
                if (typeInfo.GetGenericArguments()[0] != typeof(int)) throw new System.Exception("Not correct type");
    
                typeInfo = Media.Common.Extensions.ExpressionExtensions.SymbolExtensions.GetTypeInfo(() => (typeof(MyTestClass<int>)).GetType());
    
                if (typeInfo.GetGenericArguments()[0] != typeof(int)) throw new System.Exception("Not correct type");
    
                System.Type unboundedType = typeof(MyTestClass<>);
    
                typeInfo = Media.Common.Extensions.ExpressionExtensions.SymbolExtensions.GetTypeInfo(() => (unboundedType).GetType());
    
                System.Console.WriteLine("TypeInfo.Name" + typeInfo.Name);
    
                System.Console.WriteLine("TypeInfo.MetadataToken" + typeInfo.MetadataToken);