IDynamicMetaObjectProvider
C# in Depth の第 2 版の短い例を挙げようとしていますが、問題が発生しています。
無効な呼び出しを表現できるようにしたいのですが、失敗しています。リフレクション バインダーを使用して void メソッドを動的に呼び出すと、すべてがうまくいくので、それは可能だと確信しています。短いが完全な例を次に示します。
using System;
using System.Dynamic;
using System.Linq.Expressions;
class DynamicDemo : IDynamicMetaObjectProvider
{
public DynamicMetaObject GetMetaObject(Expression expression)
{
return new MetaDemo(expression, this);
}
public void TestMethod(string name)
{
Console.WriteLine(name);
}
}
class MetaDemo : DynamicMetaObject
{
internal MetaDemo(Expression expression, DynamicDemo demo)
: base(expression, BindingRestrictions.Empty, demo)
{
}
public override DynamicMetaObject BindInvokeMember
(InvokeMemberBinder binder, DynamicMetaObject[] args)
{
Expression self = this.Expression;
Expression target = Expression.Call
(Expression.Convert(self, typeof(DynamicDemo)),
typeof(DynamicDemo).GetMethod("TestMethod"),
Expression.Constant(binder.Name));
var restrictions = BindingRestrictions.GetTypeRestriction
(self, typeof(DynamicDemo));
return new DynamicMetaObject(target, restrictions);
}
}
class Test
{
public void Foo()
{
}
static void Main()
{
dynamic x = new Test();
x.Foo(); // Works fine!
x = new DynamicDemo();
x.Foo(); // Throws
}
}
これにより例外がスローされます。
未処理の例外: System.InvalidCastException: バインダー 'Microsoft.CSharp.RuntimeBinder.CSharpInvokeMemberBinder' の型 'DynamicDemo' を持つオブジェクトによって生成された動的バインディングの結果の型 'System.Void' は、結果の型 'System.呼び出しサイトが期待するオブジェクトです。
オブジェクトを返し、null を返すようにメソッドを変更すると、正常に動作しますが、結果を null にしたくないので、void にしたいのです。これはリフレクション バインダーでは問題なく機能しますが (Main の最初の呼び出しを参照)、動的オブジェクトでは失敗します。リフレクション バインダーのように動作するようにしたい - 結果を使用しない限り、メソッドを呼び出しても問題ありません。
ターゲットとして使用できる特定の種類の表現を見逃していませんか?