首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何将空方法调用表示为DynamicMetaObject.BindInvokeMember的结果?

如何将空方法调用表示为DynamicMetaObject.BindInvokeMember的结果?
EN

Stack Overflow用户
提问于 2009-12-03 05:22:28
回答 4查看 4.2K关注 0票数 58

我试图为C#的第二版深入地提供一个简短的IDynamicMetaObjectProvider示例,但我遇到了一些问题。

我希望能够表达一个无效的呼叫,但我失败了。我确信这是可能的,因为如果我使用反射绑定器动态调用void方法,一切都很好。下面是一个简短但完整的示例:

代码语言:javascript
复制
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“”的对象生成的动态绑定的结果类型“”DynamicDemo“”与调用站点所需的结果类型“”System.Object“”不兼容。“”

如果我将方法更改为返回object和返回值为null,则可以正常工作...但我不希望结果为空,我希望它为空。这对于反射绑定器来说工作得很好(参见Main中的第一个调用),但是对于我的动态对象却失败了。我希望它像反射绑定器一样工作--只要你不尝试使用结果,调用这个方法就可以了。

我是否错过了可以用作目标的特定类型的表达式?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2009-12-03 07:20:54

这类似于:

DLR return type

您确实需要匹配由ReturnType属性指定的返回类型。对于所有标准二进制文件,这几乎都固定为object或void (用于删除操作)。如果你知道你在打一个无效的电话,我建议你把它包起来:

代码语言:javascript
复制
Expression.Block(
    call,
    Expression.Default(typeof(object))
);

DLR过去对它所允许的内容相当宽松,它会自动提供一些最小数量的强制。我们摆脱了这一点,因为我们不想提供一组对每种语言可能有意义也可能没有意义的召集性。

听起来你想要防止:

代码语言:javascript
复制
dynamic x = obj.SomeMember();

没有办法做到这一点,总是会有一个返回值,用户可以尝试继续动态交互。

票数 26
EN

Stack Overflow用户

发布于 2009-12-03 06:02:42

我不喜欢这样,但它似乎起作用了;真正的问题似乎是binder.ReturnType进来的奇怪(并且没有被自动丢弃("pop") ),但是:

代码语言:javascript
复制
if (target.Type != binder.ReturnType) {
    if (target.Type == typeof(void)) {
        target = Expression.Block(target, Expression.Default(binder.ReturnType));
    } else if (binder.ReturnType == typeof(void)) {
        target = Expression.Block(target, Expression.Empty());
    } else {
        target = Expression.Convert(target, binder.ReturnType);
    }
}
return new DynamicMetaObject(target, restrictions);
票数 11
EN

Stack Overflow用户

发布于 2009-12-03 06:18:45

也许调用站点希望返回null,但却丢弃了结果--这个枚举看起来很有趣,尤其是"ResultDiscarded“标志……

代码语言:javascript
复制
[Flags, EditorBrowsable(EditorBrowsableState.Never)]
public enum CSharpBinderFlags
{
    BinaryOperationLogical = 8,
    CheckedContext = 1,
    ConvertArrayIndex = 0x20,
    ConvertExplicit = 0x10,
    InvokeSimpleName = 2,
    InvokeSpecialName = 4,
    None = 0,
    ResultDiscarded = 0x100,
    ResultIndexed = 0x40,
    ValueFromCompoundAssignment = 0x80
}

发人深省..。

更新:

可以从Microsoft / CSharp / RuntimeBinder / DynamicMetaObjectProviderDebugView收集到更多的提示,它被用作(我假设)调试器的可视化工具。方法TryEvalMethodVarArgs检查委托并使用结果丢弃标志(?)创建活页夹。

代码语言:javascript
复制
 Type delegateType = Expression.GetDelegateType(list.ToArray());
    if (string.IsNullOrEmpty(name))
    {
        binder = new CSharpInvokeBinder(CSharpCallFlags.ResultDiscarded, AccessibilityContext, list2.ToArray());
    }
    else
    {
        binder = new CSharpInvokeMemberBinder(CSharpCallFlags.ResultDiscarded, name, AccessibilityContext, types, list2.ToArray());
    }
    CallSite site = CallSite.Create(delegateType, binder);

..。这里是我的Reflector-foo的末尾,但是这段代码的框架看起来有点奇怪,因为TryEvalMethodVarArgs方法本身需要一个对象作为返回类型,而最后一行返回动态调用的结果。我可能弄错了表达式树。

-Oisin

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1835912

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档