Вызвать метод с общим выражением и действием в качестве параметров - PullRequest
0 голосов
/ 16 октября 2018

Мне нужно вызвать метод, который выглядит следующим образом:

public bool DoSomething<TEntity>(Expression<Func<TEntity, bool>> expression, Action<TEntity> action) where TEntity : class

Однако TEntity известен только во время выполнения.

Я знаю, как вызвать метод следующим образом:

Type classType = GetType();
MethodInfo mInfo = classType.GetMethod("DoSomething", BindingFlags.Public | BindingFlags.Instance);
MethodInfo genericMInfo = mInfo.MakeGenericMethod(GetMyType());
Object result = genericMInfo.Invoke(this, <WHAT GOES HERE>);

Как видите, я не знаю, что передать в функцию.И вот разница в Этот вопрос , где вызывается метод без параметров.

Есть ли способ, которым я могу это сделать?

РЕДАКТИРОВАТЬ: Полный пример

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

namespace Example
{
    public class Program
    {
        static void Main(string[] args)
        {
            var example = new Example();

            // Type know at compiletime:
            example.DoSomething<MyClass>((obj) => obj.Number > 2, (obj) => obj.Number = 500);

            // Type not know until runtime. Might be MyClass, MyOtherClass or MyNextClass
            Type classType = example.GetType();
            MethodInfo mInfo = classType.GetMethod("DoSomething", BindingFlags.Public | BindingFlags.Instance);
            MethodInfo genericMInfo = mInfo.MakeGenericMethod(GetMyType());

            var result = genericMInfo.Invoke(example, new object[] { /* Expression<Func<TEntity, bool>> and Action<TEntity> */ });
            // My problem now is how to create this Expression and Action even if i know TEntity only at runtime
        }

        static Type GetMyType()
        {
            // Imagine some user-input or any other dark magic here. For the example i`ll just return a type
            return typeof(MyOtherClass);
        }
    }

    public class Example
    {
        public bool DoSomething<TEntity>(Expression<Func<TEntity, bool>> expression, Action<TEntity> action) where TEntity : MyClass
        {
            // Real code does something more useful, but its the same principle
            var myList = new List<TEntity>(GetItems<TEntity>());

            if (myList.Count > 0)
            {
                var entry = myList.AsQueryable().Where(expression).FirstOrDefault();

                if (entry != null)
                {
                    action(entry);

                    return true;
                }
            }

            return false;
        }

        private IEnumerable<T> GetItems<T>()
        {
            // Real code does something diffrent
            for (int i = 0; i < 5; i++)
            {
                yield return (T)Activator.CreateInstance(typeof(T), i);
            }
        }
    }

    public class MyClass
    {
        public MyClass(int number)
        {
            Number = number;
        }

        public int Number { get; set; }
    }

    public class MyOtherClass : MyClass
    {
        public MyOtherClass(int number)
            : base(number++)
        {
        }
    }

    public class MyNextClass : MyClass
    {
        public MyNextClass(int number)
            : base(number--)
        {
        }
    }
}

1 Ответ

0 голосов
/ 16 октября 2018

К сожалению невозможно определить общие анонимные методы .

Большой вопрос: Откуда пришло ваше выражение / действие?

Из головы в голову, возможные решения включают объявление вашего действия как отдельного метода или использование вспомогательных методов для создания ваших действий / выражений.

// Create a helper method to create the expression
public static Expression<Func<TEntity, bool>> MakeExpression<TEntity>()
{
    // your custom expression here
    return x => true;
}

// Declare your action as a generic method
public static void MyAction<TEntity>(TEntity input)
{
    // your action here
}

// Then you can use it like this:
var func = typeof(Example).GetMethod("MakeExpression", BindingFlags.Public | BindingFlags.Instance).MakeGenericMethod(classType).Invoke(example, new object[0]);
var action = typeof(Example).GetMethod("MyAction", BindingFlags.Public | BindingFlags.Static).MakeGenericMethod(classType ).CreateDelegate(typeof(Action<>).MakeGenericType(classType));
genericMInfo.Invoke(example, new object[] { func, action });

Вы можете использовать ту же «фабрику выражений»подход к действию тоже:

public static Action<TEntity> MakeAction<TEntity>()
{
    // your custom action here.
    return e => { };
}

// Then:
var action = typeof(Example).GetMethod("MakeAction", BindingFlags.Public | BindingFlags.Instance).MakeGenericMethod(classType).Invoke(example, new object[0]);

Другое возможное решение будет включать динамическое построение выражения / действия с использованием класса Expression.

// Simple(!) example
var func = Expression.Lambda(Expression.Constant(true), Expression.Parameter(classType));
...