Как мне взять лямбда-выражение в качестве параметра, который возвращает метод? - PullRequest
2 голосов
/ 22 июля 2010

Я хочу иметь возможность сделать это:

var test = SomeMethod(s => s.SomeMethod);

Я могу заставить его работать со свойствами, сделав подпись метода похожей на это:

SomeMethod<TProperty>(Expression<Func<T, TProperty>> expression)

Как я могу сделатьэто работает с методами?Я знаю, что это просто, я просто скучаю по чему-то маленькому.

Ответы [ 5 ]

1 голос
/ 17 ноября 2010

Moq подходит к этому, требуя, чтобы параметры метода были заглушены специальными объектами-маркерами, такими как:

test.Setup(m => m.SomeMethod(It.IsAny<int>()));

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


Вот пример, основанный на источнике Moq (немного взломан, но показывает, как метод может быть извлечен из выражения):

    internal static void ExtractMethod<T>(Expression<Action<T>> expression)
        where T : class
    {
            var methodCall = expression.ToMethodCall();
            var method = methodCall.Method;
            var args = methodCall.Arguments.ToArray();
    }

Прямо из источника Moq:

    /// <summary>
    /// Casts the body of the lambda expression to a <see cref="MethodCallExpression"/>.
    /// </summary>
    /// <exception cref="ArgumentException">If the body is not a method call.</exception>
    public static MethodCallExpression ToMethodCall(this LambdaExpression expression)
    {
        Guard.NotNull(() => expression, expression);

        var methodCall = expression.Body as MethodCallExpression;
        if (methodCall == null)
        {
            throw new ArgumentException(string.Format(
                CultureInfo.CurrentCulture,
                Resources.SetupNotMethod,
                expression.ToStringFixed()));
        }

        return methodCall;
    }

Это будет работать с вашим кодом, но вам нужно будет передать «фиктивные» параметры, чтобы компилятор мог создать выражение.Так что если бы у вас было:

public void SomeMethod(int value, string text) {}

Тогда вы бы передали это как:

ExtractMethod(s => s.SomeMethod(0, null));
1 голос
/ 22 июля 2010

Это то, что вы ищете?

DoSomethingWithAction<T>(Func<T, Action> actionRetriever) { }
DoSomethingWithFunction<T, TResult>(Func<T, Func<TResult>> functionRetriever) { }

Вы бы назвали их так:

DoSomethingWithAction<ObjectWithMethod>(obj => obj.Method);
DoSomethingWithFunction<ObjectWithProperty>(obj => obj.Property);
0 голосов
/ 22 июля 2010

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

void SomeMethod() { }
int SomeMethod(int a, int b) { return 0; }

// ...

var test = TestMethod(s => s.SomeMethod);

Как бы компилятор мог узнать, какой из методов вы хотите проверить?

0 голосов
/ 22 июля 2010
class Program
    {
        public class Test
        {
            public bool SomeMethod(string test)
            {
                return true;
            }
        }

        static void Main(string[] args)
        {

            Test testObj = new Test();


            Func<string, bool> rule1 = AddRule(testObj, x => x.SomeMethod);

            bool rsult = rule1("ttt");

        }

        static Func<string, bool> AddRule<T>( T obj, Func<T,Func<string, bool>> func)
        {
            return func(obj);
        }


}
0 голосов
/ 22 июля 2010

Как-то так?

    public SimpleCommand( Predicate<object> canExecuteDelegate, Action<object> executeDelegate )
    {
        CanExecuteDelegate = canExecuteDelegate;
        ExecuteDelegate = executeDelegate;
    }

Вам нужно будет указать сигнатуру функции, используя Предикат или Действие.

...