Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/280.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#-如何访问Func中使用的特定类型的实例<;int>;代表_C#_Reflection_Delegates_Func - Fatal编程技术网

C#-如何访问Func中使用的特定类型的实例<;int>;代表

C#-如何访问Func中使用的特定类型的实例<;int>;代表,c#,reflection,delegates,func,C#,Reflection,Delegates,Func,在Factory.Process(..)方法中,我希望获得在Func委托的lambda表达式中使用的MyClass实例。但是,如何? 有人能帮我找个办法吗 编辑:这是一个人工的例子,证明了我的需要。这种方法背后的意图是,我希望跟踪(或订阅)委托定义中使用的所有MyClass对象。因此,每当MyClass对象值发生更改时,我都可以重新计算总值。请建议如何着手解决这个问题 注意:表达式树在我的例子中似乎没有帮助,因为我现在不能修改我的参数类型,它限制了我复杂函数定义的使用 public class

在Factory.Process(..)方法中,我希望获得在Func委托的lambda表达式中使用的MyClass实例。但是,如何? 有人能帮我找个办法吗

编辑:这是一个人工的例子,证明了我的需要。这种方法背后的意图是,我希望跟踪(或订阅)委托定义中使用的所有MyClass对象。因此,每当MyClass对象值发生更改时,我都可以重新计算总值。请建议如何着手解决这个问题

注意:表达式树在我的例子中似乎没有帮助,因为我现在不能修改我的参数类型,它限制了我复杂函数定义的使用

public class MyClass
{
    public int Value;

    public MyClass(int value)
    {
        Value = value;
    }
}

public class TestClass
{
    public void TestMethod()
    {
        var obj1 = new MyClass(10);
        var obj2 = new MyClass(20);
        Factory.Process(() => obj1.Value + obj2.Value);
    }
}

public static class Factory
{
    public static void Process(Func<int> function)
    {
        var total = function.Invoke();

        // Here, apart from invoke, I want to access the all the instances of MyClass that are used in 'function'
        // but how do I get to obj1 and obj2 objects through the 'function' delegate?
    }
}
公共类MyClass
{
公共价值观;
公共MyClass(int值)
{
价值=价值;
}
}
公共类TestClass
{
公共void TestMethod()
{
var obj1=新的MyClass(10);
var obj2=新的MyClass(20);
工厂流程(()=>obj1.Value+obj2.Value);
}
}
公共静态类工厂
{
公共静态作废流程(Func函数)
{
var total=function.Invoke();
//在这里,除了invoke之外,我还想访问“function”中使用的MyClass的所有实例
//但如何通过“函数”委托访问obj1和obj2对象?
}
}

如前所述,这是无法完成的,因为您试图访问有关确切代码的信息,因此需要检查传入的IL(因为实际的C#代码在编译后消失)


但是,可以使用
System.Linq.Expression
命名空间的元代码库,但前提是将
Func
替换为
Expression
。有了这个,您就可以遍历由lambda调用创建的。使用
表达式
代替另一个委托类型也会告诉编译器生成表达式树,而不是实际编译代码,因此如果您传递直接方法或尝试以相同方式检查非表达式树对象,这将不起作用。

首先,如果将输入参数键入just
Func
,则它不是表达式,而只是委托的lambda语法

如果希望能够访问表达式并进行一些反射和/或分析,则需要将参数键入
expression
。例如:
表达式
。这会将表达式转换为表达式树

使您能够像访问数据结构一样访问表达式。分析完表达式树后,可以调用
yourExpression.Compile()
,这将把表达式树编译成一个委托,可以作为任何其他委托(命名委托和匿名委托)调用

例如,
obj1
将通过以下方式访问:

public class MyClass
{
    public int Value { get; set; }
}

static void Main(string[] args)
{
    var obj1 = new MyClass { Value = 1 };
    var obj2 = new MyClass { Value = 2 };

    Expression<Func<int>> expr = () => obj1.Value + obj2.Value;

    BinaryExpression binaryExpr = (BinaryExpression)expr.Body;
    MemberExpression memberExpr = (MemberExpression)binaryExpr.Left;
    MemberExpression fieldExpr = (MemberExpression)memberExpr.Expression;
    ConstantExpression constantExpr = (ConstantExpression)fieldExpr.Expression;

    dynamic value = constantExpr.Value;
    MyClass some = value.obj1;
}
…您的学员应该设置所谓的
out
参数:

using System;
using System.Collections.Generic;

public class Program
{
    public class MyClass
    {
        public int Value { get; set; }  
    }

    public delegate void Func<out T>(out IDictionary<string, object> objects);

    public static void Main()
    {
        Func<int> someFunc = (out IDictionary<string, object> objects) => 
        {
            var obj1 = new MyClass { Value = 1 };
            var obj2 = new MyClass { Value = 2 };

            int result = obj1.Value + obj2.Value;

            objects = new Dictionary<string, object> { { "obj1", obj1 }, { "obj2", obj2 } };

        };

        IDictionary<string, object> objectsInFunc;

        someFunc(out objectsInFunc);

    }
}
使用系统;
使用System.Collections.Generic;
公共课程
{
公共类MyClass
{
公共int值{get;set;}
}
公共委托无效函数(out IDictionary对象);
公共静态void Main()
{
Func someFunc=(输出IDictionary对象)=>
{
var obj1=新MyClass{Value=1};
var obj2=newmyclass{Value=2};
int result=obj1.Value+obj2.Value;
objects=新字典{{“obj1”,obj1},{“obj2”,obj2};
};
IDictionary objectsInFunc;
someFunc(out objectsInFunc);
}
}

如果将
过程的参数类型更改为
表达式表达式,则可以:

public static void Process(Expression<Func<int>> expr)
{
    Func<int> function = expr.Compile();
    var total = function();

    Expression left = ((BinaryExpression)expr.Body).Left;
    Expression leftObjExpr = ((MemberExpression)left).Expression;
    Expression<Func<MyClass>> leftLambda =
        Expression.Lambda<Func<MyClass>>(leftObjExpr);
    Func<MyClass> leftFunc = leftLambda.Compile();
    MyClass obj1 = leftFunc();
    int value = obj1.Value; // ==> 10

    // Same with right operand...
}
公共静态无效进程(表达式expr)
{
Func function=expr.Compile();
var total=函数();
表达式left=((二进制表达式)expr.Body).left;
表达式leftObjExpr=((MemberExpression)left).Expression;
表达式leftLambda=
Lambda(leftObjExpr)表达式;
Func leftFunc=leftLambda.Compile();
MyClass obj1=leftFunc();
int value=obj1.value;//=>10
//与右操作数相同。。。
}
请注意,您仍然可以调用该函数;只需编译lambda表达式即可获得可调用函数


但是,这只适用于二进制表达式。如果要解析各种表达式,这将变得相当复杂。您最好使用解决此问题。

出于所有实际目的,您不能。您需要检查被授权人引用的方法的IL代码。请澄清您试图解决的实际问题。。这个例子看起来很做作,显然是为了让提问和回答问题变得容易。。。但这里似乎有些不对劲。。如果不了解实际问题,任何答案都可能是不切实际或不可接受的。。很少有人会想到,将对象传递给处理方法。。。或者对Func进行切片和切分,以获得所需的对象,可能以特定于场景的方式工作。正如Servy所说,由于对象引用作为捕获变量的值嵌入到匿名方法中,在没有实际检查匿名方法的IL并查看它使用的对象之前,没有通用的方法可以做到这一点。您需要更改基本设计以“正确的方式”执行此操作(例如,为factory方法构造一个表达式并传递该表达式,而不是实际的编译方法)。这将是一个很难解决的事实,这应该是一个强烈的暗示,表明你可能以错误的方式处理了更大的问题。@MatíasFidemraizer你的编辑是完全无效的。这个问题是关于代理的,使用反射是从代理中提取此信息的唯一方法。问题不是关于表达,这在整个问题中都很清楚。OP没有问表达,他问
public static void Process(Expression<Func<int>> expr)
{
    Func<int> function = expr.Compile();
    var total = function();

    Expression left = ((BinaryExpression)expr.Body).Left;
    Expression leftObjExpr = ((MemberExpression)left).Expression;
    Expression<Func<MyClass>> leftLambda =
        Expression.Lambda<Func<MyClass>>(leftObjExpr);
    Func<MyClass> leftFunc = leftLambda.Compile();
    MyClass obj1 = leftFunc();
    int value = obj1.Value; // ==> 10

    // Same with right operand...
}