我们能获得代表的身份吗?

Xia*_*ang 14 .net c# delegates

是否有可能生成委托的标识以区别于其他委托?想想这段代码:

Func<int, int, int> delegate1 = a, b => a + b;
Func<int, int, int> delegate2 = a, b => a + b;
Func<int, int, int> delegate3 = a, b => a - b;
let id1 = id(delegate1);
let id2 = id(delegate2);
let id3 = id(delegate3);
Assert(id1 == id2);
Assert(id1 != id3);
Run Code Online (Sandbox Code Playgroud)

我想解决的问题是,我想在.NET中缓存一些JIT编译的GPU代码.为了方便使用,我想让用户发送委托,如果委托是相同的,我们会尝试从缓存中找出GPU代码,而不是每次JIT编译它:

Parallel(outputA, inputA1, inputA2, a, b => a + b); //should JIT compile GPU code, and cache it by its identity
Parallel(outputB, inputB1, inputB2, a, b => a + b); //should NOT JIT compile GPU code, and use the cached GPU code by its identity
Run Code Online (Sandbox Code Playgroud)

一种可能的解决方案是比较表达式字符串,但仍然有问题来捕获clouser,例如:

int c = 0;
Expression<Func<int, int, int>> delegate1 = (a, b) => a + b + c;
c += 1;
Expression<Func<int, int, int>> delegate2 = (a, b) => a + b + c;
Expression<Func<int, int, int>> delegate3 = (a, b) => a - b - c;
Console.WriteLine(delegate1);
Console.WriteLine(delegate2);
Console.WriteLine(delegate1.ToString() == delegate2.ToString());
Console.ReadKey();
Run Code Online (Sandbox Code Playgroud)

正如指出由于@SWeko和@Luaan,在上述例子中,delegate1delegate2实际上是相同的.但缓存委托的目的有以下用法:

int c = 1;
Parallel(outputA, inputA1, inputA2, (a,b) => a+b); //do JIT compile of GPU code
c += 1;
Parallel(outputB, inputB1, inputB2, (a,b) => a+b); //as the delegate is same then the previouse one, it will not do JIT GPU code compiling, but then, that is wrong!
Run Code Online (Sandbox Code Playgroud)

SWe*_*eko 4

一种(相对幼稚的)方法是使用Expression<Func>s 而不是Funcs 本身,因为它们具有更详细的信息,可以让您分析内容。例如

Expression<Func<int, int, int>> delegate1 = (a, b) => a + b;
Expression<Func<int, int, int>> delegate2 = (a, b) => a + b;
Expression<Func<int, int, int>> delegate3 = (a, b) => a - b;
var id1 = id(delegate1);
var id2 = id(delegate2);
var id3 = id(delegate3);
Debug.Assert(id1 == id2);
Debug.Assert(id1 != id3);
Run Code Online (Sandbox Code Playgroud)

其中id是微不足道的:

public static string id(Expression<Func<int, int, int>> expression)
{
    return expression.ToString();
}
Run Code Online (Sandbox Code Playgroud)

通过测试。


请注意,这不是一个完整的解决方案,并且存在很多很多问题。如果需要进行全面比较,则需要考虑表达式的全部性质,包括(但不限于)进出表达式的类型、方法调用、闭包访问等。不认为这在一般情况下是可以解决的,但通常它可以限制在一些更特殊的情况下,可以解决。

  • @SWeko:请小心这种识别表达式的方式。`Func[int,int] "x =&gt; 2*x"` 将被检测为与 ``Func[int,int] "z =&gt; 2*z"`` 不同,更重要的是 `Func[double,double] "x =&gt; 2*x"` 将被检测为匹配项。如果您只使用一种类型的委托,那就没问题。但如果你打算扩大类型,这样的 ID 函数**必须至少**另外添加有关所有参数类型的信息并且是 100% 安全的,以及涉及的闭包类型......在某些情况下,你可以甚至需要有关所涉及程序集的信息.. (3认同)