无法从“方法组”转换为“操作”

时间:2017-11-28 00:15:36

标签: c# subtype

首先发布代码会更容易,然后问我为什么会收到此错误。

抽象类 - 数据包

abstract class Packet
{
    // base class!
}

我的第一个数据包

public sealed class FirstPacket : Packet
{
    // First packet implementations...
}

另一个数据包

public sealed class AnotherPacket : Packet
{
    // Another packet implementations...
}

Packet OpCodes

public enum OpCode
{
    FirstPacket,
    AnotherPacket
}

抽象类 - 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回答,派生类是其基类的一个实例,不涉及任何转换。

在我的代码中,如果FirstPacketAnotherPacket Packet,为什么我必须使用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) {
    }
}

对我来说没有意义。

1 个答案:

答案 0 :(得分:2)

首先,请注意你的lambdas

OnReceiveFirst
如果没有演员表,

就无法编译。

您可以进行演员表的原因是您对系统的逻辑有足够的了解,以决定永远不会使用SecondPacket参数调用OnReceiveFirst。因此,您得出结论,演员阵容是安全的。

另一方面,

编译器无法得出相同的结论,因此它要求您手动提供强制转换。

方法组为不需要强制转换的情况提供快捷方式。例如,如果您像这样重写public void OnReceiveFirst(Packet packetOrig) { FirstPacket packet = (FirstPacket)packetOrig; ... }

_packetHandlers.Add(OpCode.FirstPacket, OnReceiveFirst); // Compiles

您可以将它与方法组语法一起使用:

raw_input

在这里,铸造仍然是你的责任,因为如果转换抛出异常,你将能够将错误跟踪到你自己的代码,而不是某些编译器魔法。