Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/rest/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用ExpressionTree检索索引器的Setter的委托(Action<;TObject,TValue>;)_C#_.net_Delegates_Lambda - Fatal编程技术网

C# 使用ExpressionTree检索索引器的Setter的委托(Action<;TObject,TValue>;)

C# 使用ExpressionTree检索索引器的Setter的委托(Action<;TObject,TValue>;),c#,.net,delegates,lambda,C#,.net,Delegates,Lambda,我试图创建委托来访问任何属性Get&Set方法 我发现以下代码(在这篇文章中:)工作得非常好: public static class Extractor<TObject> where TObject : class { public static DelegateAccessor<TObject, TValue> GetAccessorsDelegates<TValue>(Expression<Func<TObject, TValue&g

我试图创建委托来访问任何属性Get&Set方法

我发现以下代码(在这篇文章中:)工作得非常好:

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);
    }
}
我的问题是像这样的索引器:

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

Extractor<MyObject>.DelegateAccessor(t => t.MySubTable[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])
Extractor.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);
}
publicstaticdelegateaccessor GetAccessorsDelegates(
表达式(表达式)
{
Func getter=expression.Compile();
动作设置器=null;
ParameterExpression pValue=表达式参数(typeof(TValue),“value”);
ParameterExpression pObj=表达式。参数[0];
if(expression.Body是MemberExpression)
{
表达式setterBlock=Expression.Assign(Expression.Body,pValue);
表情表达=
Lambda表达式(setterBlock,pObj,pValue);
setter=setterExpression.Compile();
}
其他的
{
var getterCall=expression.Body作为MethodCallExpression;
if(getterCall!=null)
{
var方法=getterCall.method;
if(method.IsSpecialName&&method.Name.StartsWith(“get”))
{
var parameters=method.GetParameters()
.Select(p=>p.ParameterType)
.Concat(新[]{method.ReturnType})
.ToArray();
var setterName=“set_”+method.Name.Substring(4);
变量设置法=
method.DeclaringType.GetMethod(setterName,参数);
var setterCall=Expression.Call(
getterCall.Object,setterMethod,
Concat(new[]{pValue});
变压=
Lambda(
setterCall、pObj、pValue);
setter=setterExpression.Compile();
}
}
}
返回新的DelegateAccessor(getter、setter);
}

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

替换是一个非常好的解决方案,但我搜索的是一种声明Lambda表达式的方法,该表达式直接给出索引设置器。报告的错误CS0832似乎阻止直接提取对索引器的访问…为什么需要lambda表达式(而不是与委托或
表达式相对应的表达式
)。您可以这样做,但不能将这样的lambda表达式转换为
表达式
。您的解决方案最终是好的,因为没有其他方法可以访问set_Item()方法。。。非常感谢你!!!
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);
}