4

私は C# で小さな Lisp インタープリターを書いていますが、基本的には既に動作しています。現在、関数を表すためにインターフェイスを使用しています。

public interface LispFunction
{
    object Apply(ArrayList parameters);
}

インターフェイスは、内部 (標準) 関数、ラムダ、マクロ展開、リフレクションを介した .net オブジェクト内のメソッドの呼び出しなどの複数のクラスによって実装されます。ここでは速度は問題ではなく、通訳者を仕事に連れて行って使用する喜びだけであることに注意してください.

ここで、私の小さな Lisp が、次のように、インタプリタ内で使用される任意の C# ラムダを受け入れるようにしたいと思います。

Lisp foo = new Lisp();
foo.GlobalEnvironment.AddFunction("test", (bool a, int b) => a ? b : "whoops");
foo.Eval(foo.Read("(test #t 5)")); // Should evaluate to (object) 5

最初に頭に浮かんだのは を使用することでしたが、、などFunc<...>のオーバーロードされたメソッドを多数使用する必要がありました。Func<a>Func<a, b>Func<a, b, c>

C# で、後でリフレクションを介して呼び出される任意のラムダを受け入れる可能性はありますか?

4

1 に答える 1

9

C# で、後でリフレクションを介して呼び出される任意のラムダを受け入れる可能性はありますか?

さて、任意のデリゲートを取るメソッドを書くことができます:

public void AddFunction(string name, Delegate function)

ただし、ラムダ式からの変換は特定のデリゲートとして行う必要があるため、次のものが必要になります。

Func<bool, string, string> function = (a, b) => a ? b : "whoops"
foo.GlobalEnvironment.AddFunction("test", function);

または、呼び出し内でキャストします。

foo.GlobalEnvironment.AddFunction("test",
    (Func<bool, string, string>)((a, b) => a ? b : "whoops"));

すべてのオーバーロードを1か所に配置して、完全に一般的なままにしておくことができますがAddFunction、次のような静的クラスを使用できます (少し似ていますTuple)。

public static class Func
{
    public Func<TResult> Create(Func<TResult> function) { return function; }

    public Func<T1, TResult> Create(Func<T1, TResult> function)
    {
        return function;
    }

    public Func<T1, T2, TResult> Create(Func<T1, T2, TResult> function)
    {
        return function;
    }

    // etc
}

このクラスは基本的便宜上存在します。次に、次のように呼び出します。

foo.GlobalEnvironment.AddFunction("test",
    Func.Create((bool a, string b) => a ? b : "whoops"));
于 2012-04-27T08:54:44.027 に答える