Как получить экземпляр выделенного экземпляра из выражения лямбда

У меня есть это лямбда-выражение Expression<Func<bool>> commandToExecute

Затем я передаю экземпляр класса там с помощью метода:

_commandExecuter.ProcessCommand (() => aClass.Method())

Как получить экземпляр aClass в методе ProcessCommand?

Я хочу выполнить некоторые addiontal методы этого класса или получить некоторые значения свойств.

Возможно ли это?

EDIT: Теперь я написал простой статический вспомогательный метод для получения экземпляра:

private static object GetReferredProviderInstance(Expression body)
{
    var methodCallExpression = body as MethodCallExpression;
    if (methodCallExpression != null)
    {
        var constantExpression = methodCallExpression.Object as ConstantExpression;
        if (constantExpression != null) return constantExpression.Value;
    }
    return null;
}

Вызов метода выглядит следующим образом:

Expression body = commandToExecute.Body; // this is the method parameter Expression<Func<bool>> commandToExecute
var referredProviderInstance = GetReferredProviderInstance(body);

Проблема заключается в том, что приведение в ConstantExpression приводит к Null. Таким образом, constantExpression всегда имеет значение null.

Любые идеи?

РЕДАКТИРОВАТЬ 2 Я исправил проблему...

private static object GetReferredProviderInstance(Expression body)
{
    var methodCallExpression = body as MethodCallExpression;
    if (methodCallExpression != null)
    {
        var memberExpression = methodCallExpression.Object as MemberExpression;
        if (memberExpression != null)
        {
            var constantExpression = memberExpression.Expression as ConstantExpression;
            if (constantExpression != null) return constantExpression.Value;
        }
    }
    return null;
}

Но здесь возникает новая проблема. Я получаю только экземпляр формы Windows, в которой находится выделенный экземпляр моего провайдера.

Как получить реальный объект (aClass) выражения лямбда?

Ответ 1

Это действительно возможно, но это зависит от того, что вы передаете в этот метод. Предположим, у вас есть сценарий, в котором вы передаете метод экземпляра класса, в котором вы находитесь, в ProcessCommand:

public class TestClass
{
    public void TestMethod()
    {
        ProcessCommand(() => MethodToCall());
    }
    public bool MethodToCall() { return true; }
    void ProcessCommand(Expression<Func<bool>> expression) { ... }
}

Затем вы можете использовать следующий метод ProcessCommand. Это работает только потому, что в этом экземпляре вызывается MethodToCall.

void ProcessCommand(Expression<Func<bool>> expression)
{
    var lambda = (LambdaExpression) expression;
    var methodCall = (MethodCallExpression) lambda.Body;
    var constant = (ConstantExpression) methodCall.Object;
    var myObject = constant.Value;
}

Более сложный сценарий выглядит следующим образом:

public class CallingClass
{
    public void TestMethod()
    {
        var calledClass = new CalledClass();
        ProcessCommand(() => calledClass.MethodToCall());
    }
    void ProcessCommand(Expression<Func<bool>> expression) { ... }
}
public class CalledClass
{
    public bool MethodToCall() { return true; }
}

Метод, который мы вызываем, теперь находится в другом классе и не вызывается в этом экземпляре, а в экземпляре CalledClass, называемом CalledClass. Но как компилятор передает переменную CalledClass в выражение лямбда? Ничто не определяет поле CalledClass, на которое может быть вызван метод MethodToCall.

Компилятор решает это, создавая внутренний класс с одним полем с именем CalledClass. В результате теперь метод ProcessCommand становится следующим:

public void ProcessCommand(Expression<Func<bool>> expression)
{
    // The expression is a lambda expression with a method call body.
    var lambda = (LambdaExpression) expression;
    var methodCall = (MethodCallExpression) lambda.Body;
    // The method is called on a member of some instance.
    var member = (MemberExpression) methodCall.Object;
    // The member expression contains an instance of the anonymous class that
    // defines the member...
    var constant = (ConstantExpression) member.Expression;
    var anonymousClassInstance = constant.Value;
    // ...and the member itself.
    var calledClassField = (FieldInfo) member.Member;
    // With an instance of the anonymous class and the field, we can get its value.
    var calledClass =
        (CalledClass) calledClassField.GetValue(anonymousClassInstance);
}

Немного сложнее, потому что компилятор должен создать анонимный внутренний класс.

Ответ 2

Невозможно "из коробки", вы можете взломать что-то с отражением,, но это нецелесообразно, это будет очень наоборот.
Изменить: На самом деле возможно по словам Рональда, но все-таки совсем наоборот. Скрытые побочные эффекты, подобные этому, делают код трудным для чтения и обслуживания.

Вместо этого ваш ProcessCommand должен взять либо весь объект aClass, либо более предпочтительно интерфейс IMyCommand с .Method(), а дополнительные методы и свойства, которые требуется ProcessCommand. Тогда тип aClass.GetType() должен реализовать IMyCommand.