Search code examples
.netgenericsreflectionlambdaexpression-trees

How to Return Expression<Func<TClass, TClassField>> when given only FieldInfo and TClass?


In runtime I have only TClass and a FieldInfo, and I need to generate a lambda expression that gets an instance of TClass and returns the correlate field. After constructing a MemberExpression I got stuck when trying to wrap the expression to Expression<Func<TClass, TClassField>>:

var res = Expression.Lambda<Func<TClass, TClassField>>(memberExpression, paramExp);
return res;

Because TClassField is not known during compile time. I need some strongly typed solution (no casting to object) due to 3rd party requirements. Is this even possible in C#?

EDIT I need something like this -

private void User3rdPartyLibrary<TClass>(FieldInfo fi)
{
    //Goal: call _3rdParty.Method<TClass, TClassField>(expression)

    var memberExp = Expression.Field(Expression.Parameter(typeof(TClass)), fi);
    //var lambda = some magic that returns  Expression.Lambda<Func<TClass, TClassField>>
    //      where fi.FieldType == typeof(TClassField).

    //_3rdParty.Method(lambda);
}

Signature of the 3rd party method:

public void Method<TClass, TClassMember>(Expression<Func<TClass, TClassMember>> expression);

Solution

  • public static void User3rdPartyLibrary<TClass>( FieldInfo fi )
    {
        // check types; add descriptions to exceptions
        if( fi.ReflectedType != typeof( TClass ) )
        {
            throw new ArgumentException();
        }
    
        var pe = Expression.Parameter( typeof( TClass ) );
        var me = Expression.Field( pe, fi );
        var memberExpression = Expression.Lambda( me, pe );
    
        // GetMethod call inlined for illustrative purposes
        typeof( ThirdPartyClass ).GetMethod( "ThirdPartyMethod" )
            .MakeGenericMethod( typeof( TClass ), fi.FieldType )
            .Invoke( memberExpression );
    }
    

    Then call using reflection:

    FieldInfo fi = <whatever>;
    
    // again, GetMethod call inlined for illustrative purposes
    typeof( YourType ).GetMethod( "User3rdPartyLibrary" )
        .MakeGenericMethod( fi.ReflectedType )
        .Invoke( fi );