Как я могу использовать дерево выражений для вызова универсального метода, когда тип известен только во время выполнения? - PullRequest
12 голосов
/ 12 марта 2010

Это то, что я решил с помощью отражения, но хотел бы посмотреть, как это сделать с помощью деревьев выражений.

У меня есть общая функция:

private void DoSomeThing<T>( param object[] args ) {
    // Some work is done here.
}

, что мне нужно позвонить из другого места в моем классе. Теперь, как правило, это будет просто:

DoSomeThing<int>( blah );

но только если я знаю, во время разработки я работаю с int. Когда я не знаю тип до времени выполнения, где мне нужна помощь. Как я уже сказал, я знаю, как сделать это с помощью рефлексии, но я бы хотел сделать это с помощью деревьев выражений, поскольку мое (очень ограниченное) понимание состоит в том, что я могу это сделать.

Любые предложения или указания на сайты, где я могу получить это понимание, желательно с примером кода?

Ответы [ 2 ]

6 голосов
/ 12 марта 2010

MethodInfo.MakeGenericMethod

Затем просто создайте делегат и вызовите его. (конечно, не в выражении; p)

Обновление:

Как правило, для этого я предпочитаю использовать универсальные типы, Activator.CreateInstance просто требует меньше работы. Все зависит от вашей ситуации, хотя.

5 голосов
/ 12 сентября 2014

Да, это можно сделать через деревья выражений. Преимущество состоит в том, что вы получаете делегата, поэтому повторные вызовы будут намного быстрее, чем делать MethodInfo.Invoke() снова и снова. Ключевое слово dynamic может сделать это также.

Пример:

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'

Код:

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);
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...