拡張メソッドバブルのこのご時世、ふつうのデリゲートをジェネリックデリゲートに変換したいことってあるよね。
拡張メソッドバブルのこのご時世、ジェネリックデリゲートに対して拡張メソッドが定義されていることとかも少なくない。
ということで、ふつうのデリゲートをジェネリックデリゲートとして扱いたい!なんてケースもあるようなないような。いや、きっとあります。
というわけで、いつでもデリゲートを別のデリゲート変換できるようにしておくと何かと便利っぽい感じがします。
コードは以下の通り。
using System; using System.Linq; using System.ComponentModel; namespace ConsoleApplication1 { class Program { static event CancelEventHandler TestHandler = (sender, e) => { e.Cancel = true; Console.WriteLine(sender); }; static void Main(string[] args) { TestHandler += (sender, e) => { e.Cancel = true; Console.Write(sender); Console.WriteLine(sender); }; var d1 = TestHandler.Convert<EventHandler<CancelEventArgs>>(); var d2 = TestHandler.Convert<Action<object, CancelEventArgs>>(); Console.WriteLine(d1.GetType()); d1.Invoke("hoge", new CancelEventArgs()); Console.WriteLine(d2.GetType()); d2.Invoke("fuga", new CancelEventArgs()); try { var d3 = TestHandler.Convert<Action<object, EventArgs>>(); } catch { Console.WriteLine("orz"); } Action<object, EventArgs> result = null; var isConv = TestHandler.TryConvert<Action<object, EventArgs>>(out result); Console.WriteLine(result); Console.WriteLine(isConv); Console.ReadLine(); } } public static class DelegateExtentions { public static T Convert<T>(this Delegate self) where T : class { return self.Convert(typeof(T)) as T; } private static Delegate Convert(this Delegate self, Type type) { if (self == null) return null; var delegates = self.GetInvocationList().ToList(); var convResult = delegates.ConvertAll(d => Delegate.CreateDelegate(type, d.Target, d.Method, true)); return Delegate.Combine(convResult.ToArray()); } public static bool TryConvert<T>(this Delegate self, out T result) where T : class { result = default(T); var r = result as Delegate; if (r == null) return false; return self.TryConvert(typeof(T), out r); } private static bool TryConvert(this Delegate self, Type type, out Delegate result) { result = null; if (self == null) return false; var delegates = self.GetInvocationList().ToList(); var convResult = delegates.ConvertAll(d => Delegate.CreateDelegate(type, d.Target, d.Method, false)); if (convResult.Exists(x => x == null)) return false; result = Delegate.Combine(convResult.ToArray()); return true; } } }
実行結果
System.EventHandler`1[System.ComponentModel.CancelEventArgs] hoge hogehoge System.Action`2[System.Object,System.ComponentModel.CancelEventArgs] fuga fugafuga orz False
いわゆるTryParseパターン的な意味でTryConvertってみましたが、
例外を発生させないConvertメソッドだけ作って、nullが返ってきたら変換失敗って仕様の方がシンプルかも?なーんて思ったりも。