How can I use an expression tree to call a generic method when the Type is only known at runtime?

前端 未结 2 2142
甜味超标
甜味超标 2021-02-13 11:36

This is something that I solved using reflection, but would like to see how to do it using expression trees.

I have a generic function:

private void DoSo         


        
相关标签:
2条回答
  • 2021-02-13 11:50

    MethodInfo.MakeGenericMethod

    Then just create a delegate and call it. (not in an expression, of course ;p)

    Update:

    Generally, I prefer to use generic types for this, Activator.CreateInstance just requires less work. All depends on your situation though.

    0 讨论(0)
  • 2021-02-13 12:08

    Yes, it can be done via expression trees. The advantage is that you get a delegate so repeated calls will be far faster than doing MethodInfo.Invoke() over and over again. The dynamic keyword can do this also.

    Example:

    What type would you like to use?
    decimal
    Selected type 'System.Decimal'
    Input Value:
    5.47
    <<<USING object>>>
    The object has static type 'System.Object',  dynamic type 'System.Decimal', and value '5.47'
    <<<USING dynamic>>>
    The object has static type 'System.Decimal',  dynamic type 'System.Decimal', and value '5.47'
    <<<USING reflection>>>
    The object has static type 'System.Decimal',  dynamic type 'System.Decimal', and value '5.47'
    <<<USING expression tree>>>
    The object has static type 'System.Decimal',  dynamic type 'System.Decimal', and value '5.47'
    

    Code:

    using System;
    using System.ComponentModel;
    using System.Linq;
    using System.Linq.Expressions;
    using System.Reflection;
    
    namespace SO2433436
    {
        class Program
        {
            static void LogObject<T>(T t)
            {
                Console.WriteLine("The object has static type '" + typeof(T).FullName + "',  dynamic type '" + t.GetType() + "', and value '" + t.ToString() + "'");
            }
    
            static void Main(string[] args)
            {
                Console.WriteLine("What type would you like to use?");
                string typeName = Console.ReadLine();
    
                Type userType;
                switch (typeName)
                {
                    case "byte": userType = typeof(byte); break;
                    case "sbyte": userType = typeof(sbyte); break;
                    case "ushort": userType = typeof(ushort); break;
                    case "short": userType = typeof(short); break;
                    case "uint": userType = typeof(uint); break;
                    case "int": userType = typeof(int); break;
                    case "string": userType = typeof(string); break;
                    case "decimal": userType = typeof(decimal); break;
                    default:
                        userType = Type.GetType(typeName);
                        break;
                }
    
                Console.WriteLine("Selected type '" + userType.ToString() + "'");
    
                Console.WriteLine("Input Value:");
                string val = Console.ReadLine();
    
                object o = TypeDescriptor.GetConverter(userType).ConvertFrom(val);
    
                Console.WriteLine("<<<USING object>>>");
                LogObject(o);
    
                Console.WriteLine("<<<USING dynamic>>>");
                LogObject((dynamic)o);
    
                Console.WriteLine("<<<USING reflection>>>");
                Action<object> f = LogObject<object>;
                MethodInfo logger = f.Method.GetGenericMethodDefinition().MakeGenericMethod(userType);
                logger.Invoke(null, new[] { o });
    
                Console.WriteLine("<<<USING expression tree>>>");
                var p = new[] { Expression.Parameter(typeof(object)) };
                Expression<Action<object>> e =
                    Expression.Lambda<Action<object>>(
                        Expression.Call(null,
                                        logger,
                                        Expression.Convert(p[0], userType)
                                       )
                    , p);
                Action<object> a = e.Compile();
                a(o);
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题