MultiMethod

先日マルチメソッドに感激したので、C#でむりやり定義してみる。リフレクションを使えば、それっぽくできるんじゃないかと思って。
型と対応するdelegateをTupleのListで保存して、ランタイムにマルチメソッドの引数の型でディスパッチしてやれば、それっぽくなるような気がする。ださださですが。

public static class Util {
    public delegate T0 UnaryFunction<T0, T1>(T1 a);

    public static UnaryFunction<T1, T2> MultiMethod<T1, T2>(List<Tuple<Type, UnaryFunction<T1, T2>>> functions) {
        return delegate(T2 obj) {
            UnaryFunction<T1, T2> f = functions.Find(delegate(Tuple<Type, UnaryFunction<T1, T2>> tuple) {
                return tuple.A.IsInstanceOfType(obj);
            }).B;
            return f(obj);
        };
    }
}

使い方は、

void Test() {
    Util.UnaryFunction<string, object> f = null;

    List<Tuple<Type, Util.UnaryFunction<string, object>>> l = new List<Tuple<Type, Util.UnaryFunction<string, object>>>();
    l.Add(Tuple.Make<Type, Util.UnaryFunction<string,object>>(typeof(int), delegate(object i) { return "Int"; }));
    l.Add(Tuple.Make<Type, Util.UnaryFunction<string,object>>(typeof(string), delegate(object s) { return "String"; }));
    l.Add(Tuple.Make<Type, Util.UnaryFunction<string,object>>(typeof(object), delegate(object o) { return "object"; }));

    f = Util.MultiMethod(l);

    Assert.AreEqual("Int", f((object)123));
    Assert.AreEqual("String", f((object)"hello"));
    Assert.AreEqual("object", f((object)new Integral.Geometry.Point()));
}

みたいな感じ。使いでなさすぎ。

誤算がいくつか。まずvoidは型名ではなかったことorz。UnaryFunctionとかやっても構文エラーになってしまった。次に、l.Add(...)delegateの型を推論してくれなかったこと。あとはdelegate(int i) {...}とか書いたら、UnaryFunctionに暗黙で変換してくれなかったこと。

いまいち。