【问题标题】:Cannot convert from 'method group' to Action无法从“方法组”转换为操作
【发布时间】:2017-11-28 00:15:35
【问题描述】:

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

抽象类——数据包

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
}

抽象类 - 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) {
    }
}

这对我来说没有意义。

【问题讨论】:

  • 因为你要走另一条路。 pPacket 并且您的方法需要派生类型。您可以将FirstPacketAnotherPacket 对象透明地传递给期望Packet 的方法,但反之则不行。例如,您可以将Giraffe 对象传递给期望Animal 的方法,但不能将Animal 对象传递给期望Giraffe 的方法而不进行强制转换。

标签: c# subtype


【解决方案1】:

首先,请注意您的 lambdas

p => { OnReceiveFirst((FirstPacket)p); }

没有强制转换就无法编译。

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

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

方法组为不需要强制转换的情况提供了捷径。例如,如果你像这样重写你的OnReceiveFirst

public void OnReceiveFirst(Packet packetOrig) {
    FirstPacket packet = (FirstPacket)packetOrig;
    ...
}

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

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

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

【讨论】:

    【解决方案2】:

    因为onReceiveFirstOnReceiveAnother 期望比Packet 更具体的类型。 FirstPacketAnotherPacket 都是数据包类型,但 AnotherPacket 不能代替 FirstPacket,反之亦然。

    如果OnReceiveFirstOnReceiveAnother 只需要访问Packet 类型声明的东西而不是子类中的任何东西,您可以将定义更改为:

    public void OnReceiveFirst(Packet packet) {}
    public void OnReceiveAnother(Packet packet) {}
    

    【讨论】:

      猜你喜欢
      • 2022-01-06
      • 2021-06-25
      • 2013-10-02
      • 1970-01-01
      • 2021-01-26
      • 2017-09-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多