如何将委托转换为相同的委托?

Sky*_*kyN 18 c# delegates type-conversion

委托有两种描述:第一种是在第三方程序集中:

public delegate void ClickMenuItem (object sender, EventArgs e)
Run Code Online (Sandbox Code Playgroud)

二,标准:

public delegate void EventHandler (object sender, EventArgs e);
Run Code Online (Sandbox Code Playgroud)

我正在尝试编写一个接收EventHandler类型参数的方法,并使用参数ClickMenuItem调用第三方库.

如何将ClickMenuItem转换为EventHandler?

Jon*_*eet 27

幸运的是,这很简单.你可以写:

ClickMenuItem clickMenuItem = ...; // Wherever you get this from
EventHandler handler = new EventHandler(clickMenuItem);
Run Code Online (Sandbox Code Playgroud)

反之亦然:

EventHandler handler = ...;
ClickMenuItem clickMenuItem = new ClickMenuItem(handler);
Run Code Online (Sandbox Code Playgroud)

这甚至可以在C#1.0中使用.请注意,如果您随后更改原始变量的值,则该更改将不会反映在"已转换"的变量中.例如:

ClickMenuItem click = new ClickMenuItem(SomeMethod);
EventHandler handler = new EventHandler(click);
click = null;

handler(this, EventArgs.Empty); // This will still call SomeMethod
Run Code Online (Sandbox Code Playgroud)


Ani*_*Ani 6

编辑:有第四个选项,即避免所有这些废话,并做Jon Skeet在他的回答中建议的.

像这样的东西?

public static EventHandler ToEventHandler(this ClickMenuItem clickMenuItem)
{
    if (clickMenuItem == null)
        return null;

   return (sender, e) => clickMenuItem(sender, e);
}
Run Code Online (Sandbox Code Playgroud)

反之亦然:

public static ClickMenuItem ToClickMenuItem(this EventHandler eventHandler)
{
   if (eventHandler == null)
       return null;

   return (sender, e) => eventHandler(sender, e);
}
Run Code Online (Sandbox Code Playgroud)

请注意,编译器会推断将lamda表达式转换为哪种委托类型.

编辑:如果您愿意,也可以使用匿名代表.

EventHandler eventHandler =  delegate(object sender, EventArgs e)
                             { 
                                clickMenuItem(sender, e); 
                             };
return eventHandler; // can be inlined, type-inference works fine
Run Code Online (Sandbox Code Playgroud)

第三种选择当然是自己写一个封闭类.我不会真的推荐这个,但它让你了解编译器对匿名方法的作用.就像是:

public static class ClickMenuItemExtensions
{
    public static EventHandler ToEventHandler(this ClickMenuItem clickMenuItem)
    {
        if (clickMenuItem == null)
            return null;

        // new EventHandler not required, included only for clarity 
        return new EventHandler(new Closure(clickMenuItem).Invoke);
    }

    private sealed class Closure
    {
        private readonly ClickMenuItem _clickMenuItem;

        public Closure(ClickMenuItem clickMenuItem)
        {
            _clickMenuItem = clickMenuItem;
        }

        public void Invoke(object sender, EventArgs e)
        {
            _clickMenuItem(sender, e);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Tho*_*que 5

除了其他答案之外,如果要在编译时不知道类型的情况下在兼容的委托类型之间进行转换,您可以执行以下操作:

static Delegate ConvertDelegate(Delegate sourceDelegate, Type targetType)
{
    return Delegate.CreateDelegate(
            targetType,
            sourceDelegate.Target,
            sourceDelegate.Method);
}
Run Code Online (Sandbox Code Playgroud)

如果您需要动态订阅事件,它会很有用.