【问题标题】:Compiler error on passing member function to a delegate将成员函数传递给委托时的编译器错误
【发布时间】:2011-06-14 20:47:42
【问题描述】:

当我尝试将成员函数(来自 SoundManager 类)传递给委托(在 EventManager 中)时,出现编译器错误。
错误:参数 2:无法从“方法组”转换为“Event_Sharp.FunctionHandler”
代码:

public delegate void FunctionHandler(IEvent evnt);

事件管理器::

public void RegisterListener(int type, FunctionHandler handler)
{
    // ...
}

SoundManager.cs(构造函数):

EventManager.Instance.RegisterListener(Event_Bullet_Fired.GetType(), HandleBulletFired );

HandleBulletFired 是 SoundManager 的成员:

void HandleBulletFired(Event_Bullet_Fired evnt)
{
    // ...
}

并且,Event_Bullet_Fired 实现了 IEvent 接口。有人可以告诉我为什么会出现此错误以及为什么不能将 HandleBulletFired 用作委托吗?

【问题讨论】:

    标签: c# delegates compiler-errors function-pointers


    【解决方案1】:

    你所做的不是类型安全的,因此编译器会抱怨。

    这样想:

    interface IAnimal { }
    class Lion : IAnimal { public void Roar() {} }
    class Giraffe: IAnimal { }
    delegate void D(IAnimal animal);
    static void M(Lion lion) { lion.Roar(); }
    

    现在你说

    D d = M;
    

    你明白为什么这不起作用吗?因为没有什么能阻止你说出来

    d(new Giraffe());
    

    现在你刚刚发出了长颈鹿的吼叫声。或者,更确切地说,您刚刚使 CLR 崩溃。

    为防止您这样做,编译器会停止进行不安全分配的尝试。

    请注意,您可以走另一条路:

    delegate void D2(Lion lion);
    static void M2(IAnimal animal) {}
    ...
    D2 d2 = M2;
    

    因为现在您要将 Lion 传递给 d2,它会将 IAnimal 传递给 M2,而 Lion 保证会实现 IAnimal。

    这种说法的高级说法是委托转换的方法组在其参数类型上是逆变的,在它们的返回类型上是协变的。

    有关更多信息,请参阅我关于协变和逆变的系列博客文章。

    【讨论】:

    • 感谢您的解释!我现在确切地了解发生了什么以及为什么编译器阻止我这样做。我正在将一些代码从 C++ 移植到 C#,在那里我使用了一个基指针......以及它的 C++,你可以在那里做各种疯狂的事情 :)
    • @brainydexter:这让我怀疑你的 C++ 代码也有错误,但运行时错误而不是编译器错误。
    • @Brian:我确保向函数发送正确的事件,但很高兴知道这个潜在的运行时错误。
    【解决方案2】:

    Event_Bullet_Fired.GetType() 看起来不像 RegisterListener 方法需要返回 int:

    public void RegisterListener(int type, FunctionHandler handler)
    

    更新

    我认为错误的原因是Event_Bullet_FiredIEvent 更具体。 尝试在 HandleBulletFired 方法声明中将 Event_Bullet_Fired 替换为 IEvent

    void HandleBulletFired(IEvent evt)
    {
        Event_Bullet_Fired bullerFiredEvent = (Event_Bullet_Fired)evt;
        // ...
    }
    

    【讨论】:

    • 'GetType()' 是为 Event_Bullet_Fired 实现的。另外,我将其替换为 1,我仍然得到相同的错误
    • 谢谢!这解决了它,但我担心的是这个。 Event_Bullet_Fired实现了IEvent接口,为什么编译时报错?
    【解决方案3】:

    也许你应该尝试将HandleBulletFired 转换为FunctionHandler

    EventManager.Instance.RegisterListener(Event_Bullet_Fired.GetType(), (FunctionHandler)HandleBulletFired );
    

    【讨论】:

    • 在投射时,它抱怨,HandleBulletFired 没有重载匹配委托 FunctionHandler
    • 好的,那么也许将 Event_Bullet_Fired 转换为 IEvent?编译器似乎很困惑,(可能)有一个组方法或一个具有多个重载的方法,并且方法调用不明确。无论如何,现在您知道 HandleBulletFired 与 FunctionHandler 不匹配。
    • 在之前的评论中,我的意思是有一组方法 HandleBulletFired 并且编译器无法解析其中哪个是合适的 - 所以你必须将 HandleBulletFired 转换为 FunctionHandler 或 Event_Bullet_Fired 转换为 IEvent 或两者。
    • 我只有一个具有该名称的函数,但是,是的,更改 Andrew 提到的签名(见上文),完成了这项工作。谢谢
    猜你喜欢
    • 2022-08-19
    • 1970-01-01
    • 2019-09-02
    • 2019-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-07
    相关资源
    最近更新 更多