4

私は最近、次のことが機能することが実証された例を見ました。

T Add<T>(dynamic a, dynamic b)
{
    return a + b;
}

Add<string>("hello", "world");  // Returns "helloworld"

ただし、式を使用して「一般的な」Add関数を作成しようとすると、次のようになります。

ParameterExpression left = Expression.Parameter(typeof(T), "left");
ParameterExpression right = Expression.Parameter(typeof(T), "right");
var add = Expression.Lambda<Func<T, T, T>>(Expression.Add(left, right), left, right).Compile();  // Fails with System.InvalidOperationException : The binary operator Add is not defined for the types 'System.String' and 'System.String' when T == String.

次に、この関数を文字列で使用しましたが、String型は実際には+演算子を実装しておらず、String.Concat()の単なる構文糖衣であるため失敗します。

では、動的にこれを機能させるにはどうすればよいでしょうか。実行時に、String.Concat()を使用して+が書き換えられるポイントを過ぎていることがわかりました。

4

3 に答える 3

6

dynamicC#コンパイラルールを複製するランタイムヘルパー関数を使用します。これらのルールの1つは、フレームワークによって演算子が定義されていない場合でもオブジェクトを許可+します。カスタム演算子のオーバーロードがないstringなどの標準的な数値タイプも、コンパイラによって実行され、を使用する場合は実行時に実行する必要があります。これが、Microsoft.CSharp.dllへの参照が必要な理由です。これらのヘルパー関数がないと機能しません。intdynamicdynamic

于 2012-07-29T07:11:32.693 に答える
3

ドキュメントに基づいて、代わりにstatic の がどこにあるExpression.Add(left, right)かを言うことができます。Expression.Add(left, right, method)methodMethodInfoString.Concat(String, String)

var method = typeof(string).GetMethod("Concat", new[] { typeof(string), typeof(string), });

編集:うーん、私の答えは要点を逃しています。+興味深い質問は、コンパイラが型チェックなしで通過させた a を解決しようとするときに、ランタイムはどのような操作を考慮するかということです。数値型のビルトイン追加? 文字列連結?デリゲート連結?ユーザー定義の演算子のオーバーロード?

于 2012-07-29T06:22:39.390 に答える
0

最初の例では、 a と be はまだ文字列です(これを試してください):

// Define other methods and classes here
T Add<T>(dynamic a, dynamic b)
{
    Console.WriteLine(a.GetType());
    Console.WriteLine(b.GetType());
    return a + b;
}

多分これはより理にかなっていますか?

void Main()
{
var x = Add<string>(new { val = "hello"},new { val = "world"});  // Returns "hello world"  
Console.WriteLine(x);
}

// Define other methods and classes here
T Add<T>(dynamic a, dynamic b)
{
    return a.val + b.val;
}
于 2012-07-29T06:08:42.903 に答える