J'essaie de donner un court exemple de IDynamicMetaObjectProvider
pour la deuxième édition de C# in Depth, et je rencontre des problèmes.
Je veux être capable d'exprimer un appel au vide, et j'échoue. Je suis sûr que c'est possible, car si j'appelle dynamiquement une méthode void en utilisant le binder de réflexion, tout va bien. Voici un exemple court mais complet :
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
}
}
Une exception est alors levée :
Exception non gérée : System.InvalidCastException : L'adresse type de résultat 'System.Void' de la fonction liaison dynamique produite par l'objet avec le type 'DynamicDemo' pour le liant. Microsoft.CSharp.RuntimeBinder.CSharpInvokeMemberBinder'. n'est pas compatible avec le type de résultat 'System.Object' attendu par le site d'appel. site d'appel.
Si je modifie la méthode pour qu'elle renvoie un objet et retourne null, cela fonctionne bien... mais je ne veux pas que le résultat soit null, je veux qu'il soit void. Cela fonctionne bien pour le binder de réflexion (voir le premier appel dans Main) mais cela échoue pour mon objet dynamique. Je veux que cela fonctionne comme le liant par réflexion - il est possible d'appeler la méthode, tant que vous n'essayez pas d'utiliser le résultat.
Ai-je manqué un type d'expression particulier que je peux utiliser comme cible ?