将eventhandler作为方法参数传递

时间:2014-04-04 19:28:30

标签: c# delegates

我试图将事件处理程序传递给我的一个方法。这可能看起来很愚蠢,但我似乎无法找到办法。

我在这里有几个关于SO的问题,但我仍然无法克服它。

我有以下方法签名

public void SyncWithInfo(Action<object, EventArgs> cellValueChanged,
    int indexValeurFr, int indexValeurEn, int indexUnite)

我试图用这段代码调用它

private void myMethod()
{
    dgvform.SyncWithInfo(dgvform_CellValueChanged, valeur.Index,
        valeurEN.Index, unite.Index);
}

private void dgvform_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
    //stuff
}

我有以下错误:

  

无法转换为&#39;方法组&#39;到'System.Action<object, System.EventArgs>'

我在某处here处有一个红色的东西,在没有任何参数的情况下通过名称直接引用方法被认为是一个方法组&#39;因为该方法可能存在X重载。

所以这是我的问题:如何将我的事件处理程序作为方法的参数传递?

3 个答案:

答案 0 :(得分:4)

我认为SyncWithInfo签名必须使用EventArg的显式类型。所以方法签名看起来像:

public void SyncWithInfo(Action<object, DataGridViewCellEventArgs> cellValueChanged,
    int indexValeurFr, int indexValeurEn, int indexUnite)

答案 1 :(得分:2)

接受的答案有解决方案,但尝试提供一些解释:

通常,您可以将派生类型分配给其基本类型:

EventArgs e = new DataGridViewCellEventArgs();

然而,当你开始处理泛型(这是你的行为,一个通用的委托)时,事情变得有些奇怪。你必须开始处理一个叫做方差的概念。默认情况下,泛型不是协变的。协方差意味着您可以使用派生类型作为类型参数。逆变意味着你可以走另一条路。

某些泛型,如IEnumerable,被标记为协变(通过使用T作为其类型参数)。这就是你能做到的原因:

IEnumerable<object> = new List<String>();

操作委托不是协变的,因此示例代码不会编译。

MSDN上的协方差和逆差。

答案 2 :(得分:2)

对@LordTakkera的解释是错误的(对不起)。它与此处与泛型相关的方差无关。对于普通(非泛型)委托,您将遇到同样的问题。

方法可以接受具有比方法头中指定的参数类型更多派生类型的值。我们在这里要考虑的方法是我们想要作为参数传递给另一个方法的事件处理程序。如果此事件处理程序需要类型为DataGridViewCellEventArgs的参数,则它将不接受类型为EventArgs的参数,该参数的派生程度较低。

如果您可以将此事件处理程序作为委托传递给另一个方法的类型Action<object, EventArgs>的参数,则此另一个方法可以调用我们的事件处理程序并将其传递给EventArgs参数;但是,事件处理程序需要DataGridViewCellEventArgs参数。

另一方面,相反的情况有效。

private void AcceptsEventHandler(Action<object, DataGridViewCellEventArgs> handler)
{
    // handler is SomeEventHandler if we call:
    //           AcceptsEventHandler(SomeEventHandler);

    handler(this, new DataGridViewCellEventArgs(1, 2));
}

private void SomeEventHandler(object sender, EventArgs e)
{
   // We are getting a DataGridViewCellEventArgs as second argument here, which is ok.
}

这有效:

AcceptsEventHandler(SomeEventHandler);