即使签名匹配,也无法将一种类型的委托分配给另一种类型

Hob*_*bes 11 c# lambda delegates type-conversion func

我的病态好奇让我想知道为什么以下失败:

// declared somewhere
public delegate int BinaryOperation(int a, int b);

// ... in a method body
Func<int, int, int> addThem = (x, y) => x + y;

BinaryOperation b1 = addThem; // doesn't compile, and casting doesn't compile
BinaryOperation b2 = (x, y) => x + y; // compiles!
Run Code Online (Sandbox Code Playgroud)

Ani*_*Ani 16

C#对"结构"打字的支持非常有限.特别是,您不能仅仅因为它们的声明类似而从一个委托类型转换为另一个委托类型.

从语言规范:

C#中的委托类型是名称等价的,在结构上不等同.具体而言,具有相同参数列表和返回类型的两种不同委托类型被视为不同的委托类型.

尝试以下之一:

// C# 2, 3, 4 (C# 1 doesn't come into it because of generics)
BinaryOperation b1 = new BinaryOperation(addThem);

// C# 3, 4
BinaryOperation b1 = (x, y) => addThem(x, y);
var b1 = new BinaryOperation(addThem);
Run Code Online (Sandbox Code Playgroud)

  • 非结构化类型的原因是因为委托定义可能具有语义.您不应该将"Func"分配给"SecureFunc","PureFunc"或"NoSideEffectsFunc"等等.实际上,实际上没有人能够创建具有语义的委托类型; 如果我们不得不重新做一遍,代表们可能会更加结构化. (12认同)
  • 在该特定示例中,可以进一步假设编译器可以识别无副作用的方法并且具有给定委托类型的特殊知识,以警告您是否做错了.但总的来说,在某些时候,开发人员必须负责正确使用这些工具. (2认同)

con*_*tor 7

这是一个类似的问题:为什么不编译?

// declared somewhere
struct Foo {
    public int x;
    public int y;
}

struct Bar {
    public int x;
    public int y;
}

// ... in a method body
Foo item = new Foo { x = 1, y = 2 };

Bar b1 = item; // doesn't compile, and casting doesn't compile
Bar b2 = new Bar { x = 1, y = 2 }; // compiles!
Run Code Online (Sandbox Code Playgroud)

在这种情况下,演员阵容看起来更自然,但实际上是同样的原因.