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

前端 未结 2 2130
甜味超标
甜味超标 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 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
    <<>>
    The object has static type 'System.Object',  dynamic type 'System.Decimal', and value '5.47'
    <<>>
    The object has static type 'System.Decimal',  dynamic type 'System.Decimal', and value '5.47'
    <<>>
    The object has static type 'System.Decimal',  dynamic type 'System.Decimal', and value '5.47'
    <<>>
    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)
            {
                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("<<>>");
                LogObject(o);
    
                Console.WriteLine("<<>>");
                LogObject((dynamic)o);
    
                Console.WriteLine("<<>>");
                Action f = LogObject;
                MethodInfo logger = f.Method.GetGenericMethodDefinition().MakeGenericMethod(userType);
                logger.Invoke(null, new[] { o });
    
                Console.WriteLine("<<>>");
                var p = new[] { Expression.Parameter(typeof(object)) };
                Expression> e =
                    Expression.Lambda>(
                        Expression.Call(null,
                                        logger,
                                        Expression.Convert(p[0], userType)
                                       )
                    , p);
                Action a = e.Compile();
                a(o);
            }
        }
    }
    
        

    提交回复
    热议问题