c# - 使用 ExpressionTree 将委托(delegate) (Action<TObject, TValue>) 检索到索引器的 Setter

标签 c# .net delegates lambda

我正在尝试创建委托(delegate)来访问任何 Property Get 和 Set 方法。

我发现以下代码(在这篇文章中:driis about deep properties)非常有效:

public static class Extractor<TObject> where TObject : class
{
    public static DelegateAccessor<TObject, TValue> GetAccessorsDelegates<TValue>(Expression<Func<TObject, TValue>> expression)
    {
        Func<TObject, TValue> getter = expression.Compile();

        ParameterExpression pObj = expression.Parameters[0];
        ParameterExpression pValue = Expression.Parameter(typeof(TValue), "value");
        BlockExpression setterBlock = Expression.Block(Expression.Assign(expression.Body, pValue));
        Expression<Action<TObject, TValue>> setterExpression = Expression.Lambda<Action<TObject, TValue>>(setterBlock, pObj, pValue);
        Action<TObject, TValue> setter = setterExpression.Compile();

        return new DelegateAccessor<TObject, TValue>(getter,setter);
    }
}

例如:当我从参数中的表达式创建 setter 时,我获得了如下这些 getter 和 setter 委托(delegate):

get : (t => t.ID)
set : (t, value) => { t.ID = value}

我的问题是像这样的索引器:

public object this[int id]

当我调用索引器的子属性时,没有问题。它工作正常,因为索引器,内部命名为“Item”,通过读取它来访问:

Extractor<MyObject>.DelegateAccessor(t => t.MySubTable[2].MyProperty)

表达式是:

t => t.MySubTable.get_Item(2).MyProperty

但我没有找到获取内部 setter 表达式的方法。我的目标是获得这样的东西:

(t, value) => { t.MySubTable.set_Item(2, value) }

但我不能像这样对 Lambda 使用赋值:

(t,v) => t.SubStrings[0] = v

我收到错误 CS0832:表达式树不能包含赋值运算符。

有没有一种方法可以编写 Lambda 表达式以便在表达式> 参数中找到“set_Item(2, value)”主体???

提前致谢,我知道这是一个很难的问题...

最佳答案

如果我没理解错的话,您想要一种与您已有的方法完全一样的方法,但它也适用于类似的东西

Extractor<MyObject>.DelegateAccessor(t => t.MySubTable[2])

如果是这样的话,像这样的东西应该可以工作:

public static DelegateAccessor<TObject, TValue> GetAccessorsDelegates<TValue>(
    Expression<Func<TObject, TValue>> expression)
{
    Func<TObject, TValue> getter = expression.Compile();

    Action<TObject, TValue> setter = null;
    ParameterExpression pValue = Expression.Parameter(typeof(TValue), "value");
    ParameterExpression pObj = expression.Parameters[0];
    if (expression.Body is MemberExpression)
    {
        Expression setterBlock = Expression.Assign(expression.Body, pValue);
        Expression<Action<TObject, TValue>> setterExpression =
            Expression.Lambda<Action<TObject, TValue>>(setterBlock, pObj, pValue);
        setter = setterExpression.Compile();
    }
    else
    {
        var getterCall = expression.Body as MethodCallExpression;
        if (getterCall != null)
        {
            var method = getterCall.Method;
            if (method.IsSpecialName && method.Name.StartsWith("get_"))
            {
                var parameters = method.GetParameters()
                                       .Select(p => p.ParameterType)
                                       .Concat(new[] { method.ReturnType })
                                       .ToArray();
                var setterName = "set_" + method.Name.Substring(4);
                var setterMethod =
                    method.DeclaringType.GetMethod(setterName, parameters);
                var setterCall = Expression.Call(
                    getterCall.Object, setterMethod,
                    getterCall.Arguments.Concat(new[] { pValue }));
                var setterExpression =
                    Expression.Lambda<Action<TObject, TValue>>(
                        setterCall, pObj, pValue);
                setter = setterExpression.Compile();
            }
        }
    }

    return new DelegateAccessor<TObject, TValue>(getter, setter);
}

第一部分基本上是您拥有的方法的副本。第二部分检查表达式是否是对 getter 方法的调用,如果是,则将其替换为对 setter 方法的调用。有一些关于参数的工作,但除此之外,非常简单。

关于c# - 使用 ExpressionTree 将委托(delegate) (Action<TObject, TValue>) 检索到索引器的 Setter,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6628559/

相关文章:

c# - 从 C# 调用 C++ dll 函数

c# - 在任务完成时使用不带异步的等待来处理任务

c# - 如何将对象转换为动态类型?

.net - 有没有办法创建 .net 用户控件以便在 delphi 表单上使用它们?

c# - SpinWait.SpinUntil 的替代方案

c# - 你能在一个衬里中获得最大长度的 String.Split 吗?

c# - 如何创建多线程 Dll

ios - 带有委托(delegate)的 objective-c 文本字段不起作用

ios - 将数据从子 VC 传递回 Collection View Cell

ios - 从一个 viewController 调用方法,同时显示另一个 viewController