无法从 'method group' 转换为 Action
Cannot convert from 'method group' to Action
先post代码会更容易,然后问我为什么会收到这个错误。
摘要class - 数据包
abstract class Packet
{
// base class!
}
我的第一个包裹
public sealed class FirstPacket : Packet
{
// First packet implementations...
}
另一个数据包
public sealed class AnotherPacket : Packet
{
// Another packet implementations...
}
数据包操作码
public enum OpCode
{
FirstPacket,
AnotherPacket
}
摘要class - BaseConnection
public abstract class BaseConnection
{
private Dictionary<OpCode, Action<Packet>> _packetHandlers;
public Connection() {
_packetHandlers = new Dictionary<OpCode, Action<Packet>>();
}
}
最后,我的客户
public sealed class Client : BaseConnection
{
public Client() : base() {
// Here will throw the errors...
// CS1503 Argument 2: cannot convert from 'method group' to 'Action<Packet>'
_packetHandlers.Add(OpCode.FirstPacket, OnReceiveFirst);
_packetHandlers.Add(OpCode.AnotherPacket, OnReceiveAnother);
}
public void OnReceiveFirst(FirstPacket packet) {
}
public void OnReceiveAnother(AnotherPacket packet) {
}
}
根据 this 的回答,派生的 class 是其基础 class 的一个实例,不涉及转换。
在我的代码中,如果 FirstPacket
和 AnotherPacket
是 Packet
,为什么我必须 "cast" 使用 lambda ?
public sealed class Client : BaseConnection
{
public Client() : base() {
// This works...
_packetHandlers.Add(OpCode.FirstPacket, p => { OnReceiveFirst((FirstPacket)p); });
_packetHandlers.Add(OpCode.AnotherPacket, p => { OnReceiveAnother((AnotherPacket)p); });
}
public void OnReceiveFirst(FirstPacket packet) {
}
public void OnReceiveAnother(AnotherPacket packet) {
}
}
这对我来说没有意义。
因为 onReceiveFirst
和 OnReceiveAnother
期望比 Packet
更具体的类型。 FirstPacket
和AnotherPacket
都是包的类型,但是AnotherPacket
不能代替FirstPacket
,反之亦然。
如果 OnReceiveFirst
和 OnReceiveAnother
只需要访问由 Packet
类型声明的东西而不是子类中的任何东西,您可以将定义更改为:
public void OnReceiveFirst(Packet packet) {}
public void OnReceiveAnother(Packet packet) {}
首先,请注意您的 lambdas
p => { OnReceiveFirst((FirstPacket)p); }
没有转换将无法编译。
之所以可以进行强制转换,是因为您对系统的逻辑了解得足够多,可以决定永远不会使用 SecondPacket
的参数调用 OnReceiveFirst
。因此,您得出结论,演员表是安全的。
另一方面,编译器无法得出相同的结论,因此它会要求您手动提供转换。
方法组为不需要强制转换的情况提供了一种快捷方式。例如,如果您像这样重写 OnReceiveFirst
public void OnReceiveFirst(Packet packetOrig) {
FirstPacket packet = (FirstPacket)packetOrig;
...
}
您可以将其与方法组语法一起使用:
_packetHandlers.Add(OpCode.FirstPacket, OnReceiveFirst); // Compiles
在这里,转换仍然是你的责任,因为如果转换抛出异常,你将能够将错误追溯到你自己的代码,而不是某些编译器魔法。
先post代码会更容易,然后问我为什么会收到这个错误。
摘要class - 数据包
abstract class Packet
{
// base class!
}
我的第一个包裹
public sealed class FirstPacket : Packet
{
// First packet implementations...
}
另一个数据包
public sealed class AnotherPacket : Packet
{
// Another packet implementations...
}
数据包操作码
public enum OpCode
{
FirstPacket,
AnotherPacket
}
摘要class - BaseConnection
public abstract class BaseConnection
{
private Dictionary<OpCode, Action<Packet>> _packetHandlers;
public Connection() {
_packetHandlers = new Dictionary<OpCode, Action<Packet>>();
}
}
最后,我的客户
public sealed class Client : BaseConnection
{
public Client() : base() {
// Here will throw the errors...
// CS1503 Argument 2: cannot convert from 'method group' to 'Action<Packet>'
_packetHandlers.Add(OpCode.FirstPacket, OnReceiveFirst);
_packetHandlers.Add(OpCode.AnotherPacket, OnReceiveAnother);
}
public void OnReceiveFirst(FirstPacket packet) {
}
public void OnReceiveAnother(AnotherPacket packet) {
}
}
根据 this 的回答,派生的 class 是其基础 class 的一个实例,不涉及转换。
在我的代码中,如果 FirstPacket
和 AnotherPacket
是 Packet
,为什么我必须 "cast" 使用 lambda ?
public sealed class Client : BaseConnection
{
public Client() : base() {
// This works...
_packetHandlers.Add(OpCode.FirstPacket, p => { OnReceiveFirst((FirstPacket)p); });
_packetHandlers.Add(OpCode.AnotherPacket, p => { OnReceiveAnother((AnotherPacket)p); });
}
public void OnReceiveFirst(FirstPacket packet) {
}
public void OnReceiveAnother(AnotherPacket packet) {
}
}
这对我来说没有意义。
因为 onReceiveFirst
和 OnReceiveAnother
期望比 Packet
更具体的类型。 FirstPacket
和AnotherPacket
都是包的类型,但是AnotherPacket
不能代替FirstPacket
,反之亦然。
如果 OnReceiveFirst
和 OnReceiveAnother
只需要访问由 Packet
类型声明的东西而不是子类中的任何东西,您可以将定义更改为:
public void OnReceiveFirst(Packet packet) {}
public void OnReceiveAnother(Packet packet) {}
首先,请注意您的 lambdas
p => { OnReceiveFirst((FirstPacket)p); }
没有转换将无法编译。
之所以可以进行强制转换,是因为您对系统的逻辑了解得足够多,可以决定永远不会使用 SecondPacket
的参数调用 OnReceiveFirst
。因此,您得出结论,演员表是安全的。
另一方面,编译器无法得出相同的结论,因此它会要求您手动提供转换。
方法组为不需要强制转换的情况提供了一种快捷方式。例如,如果您像这样重写 OnReceiveFirst
public void OnReceiveFirst(Packet packetOrig) {
FirstPacket packet = (FirstPacket)packetOrig;
...
}
您可以将其与方法组语法一起使用:
_packetHandlers.Add(OpCode.FirstPacket, OnReceiveFirst); // Compiles
在这里,转换仍然是你的责任,因为如果转换抛出异常,你将能够将错误追溯到你自己的代码,而不是某些编译器魔法。