RuntimeBinderException

RuntimeBinderException

本文介绍了处理动态时抛出的很多第一次机会 Microsoft.CSharp.RuntimeBinderExceptions的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 C# 中有一个标准的动态字典"类型类 -

class Bucket : DynamicObject{readonly 字典m_dict = new Dictionary();public override bool TrySetMember(SetMemberBinder binder, object value){m_dict[binder.Name] = 值;返回真;}public override bool TryGetMember(GetMemberBinder binder, out object result){return m_dict.TryGetValue(binder.Name, out result);}}

现在我称之为,如下:

static void Main(string[] args){动态 d = 新桶();d.Name = "猎户座";//2 运行时绑定器异常Console.WriteLine(d.Name);//2 运行时绑定器异常}

该应用执行您期望的操作,但调试输出如下所示:

Microsoft.CSharp.dll 中发生了Microsoft.CSharp.RuntimeBinder.RuntimeBinderException"类型的第一次机会异常Microsoft.CSharp.dll 中发生了Microsoft.CSharp.RuntimeBinder.RuntimeBinderException"类型的第一次机会异常ScratchConsoleApplication.vshost.exe"(托管(v4.0.30319)):加载匿名托管的动态方法程序集"Microsoft.CSharp.dll 中发生了Microsoft.CSharp.RuntimeBinder.RuntimeBinderException"类型的第一次机会异常Microsoft.CSharp.dll 中发生了Microsoft.CSharp.RuntimeBinder.RuntimeBinderException"类型的第一次机会异常

任何访问动态成员的尝试似乎都会向调试日志输出RuntimeBinderException.虽然我知道第一次机会异常本身并不是问题,但这确实给我带来了一些问题:

  1. 我经常将调试器设置为中断异常",因为我正在编写 WPF 应用程序,否则所有异常最终都会转换为 DispatcherUnhandledException,以及所有实际的你想要的信息丢失了.WPF 很烂.

  2. 只要我遇到任何使用 dynamic 的代码,调试输出日志就会变得毫无用处.我关心的所有有用的跟踪行都隐藏在所有无用的 RuntimeBinderExceptions

有什么办法可以关闭它,或者 RuntimeBinder 不幸就是这样构建的?

谢谢,猎户座

解决方案

每当解析动态对象上的属性时,运行时都会尝试查找在编译时定义的属性.来自 DynamicObject 文档:

您也可以将自己的成员添加到从 DynamicObject 派生的类班级.如果你的班级定义属性并覆盖TrySetMember 方法,动态语言运行时 (DLR) 首先使用语言绑定器寻找静态类中属性的定义.如果没有这样的属性,DLR调用 TrySetMember 方法.

RuntimeBinderException 每当运行时找不到静态定义的属性时就会抛出(即在 100% 静态类型世界中会出现编译器错误).来自 MSDN 文章

...RuntimeBinderException 表示一个在某种意义上无法绑定常见的编译器错误...

有趣的是,如果您使用 ExpandoObject,在尝试使用该属性时只会得到一个异常:

dynamic bucket = new ExpandoObject();桶.SomeValue = 45;int value = bucket.SomeValue;//<-- 这里的异常

也许 ExpandoObject 可以作为替代方案?如果它不合适,您需要考虑实施 IDynamicMetaObjectProvider,这就是 ExpandoObject 动态分派的方式.但是,它没有很好的文档记录,MSDN 会向您推荐 DLR CodePlex 以获取更多信息.

I've got a standard 'dynamic dictionary' type class in C# -

class Bucket : DynamicObject
{
    readonly Dictionary<string, object> m_dict = new Dictionary<string, object>();

    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
        m_dict[binder.Name] = value;
        return true;
    }

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        return m_dict.TryGetValue(binder.Name, out result);
    }
}

Now I call it, as follows:

static void Main(string[] args)
{
    dynamic d = new Bucket();
    d.Name = "Orion"; // 2 RuntimeBinderExceptions
    Console.WriteLine(d.Name); // 2 RuntimeBinderExceptions
}

The app does what you'd expect it to, but the debug output looks like this:

A first chance exception of type 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' occurred in Microsoft.CSharp.dll
A first chance exception of type 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' occurred in Microsoft.CSharp.dll
'ScratchConsoleApplication.vshost.exe' (Managed (v4.0.30319)): Loaded 'Anonymously Hosted DynamicMethods Assembly'
A first chance exception of type 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' occurred in Microsoft.CSharp.dll
A first chance exception of type 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' occurred in Microsoft.CSharp.dll

Any attempt to access a dynamic member seems to output a RuntimeBinderException to the debug logs. While I'm aware that first-chance exceptions are not a problem in and of themselves, this does cause some problems for me:

  1. I often have the debugger set to "break on exceptions", as I'm writing WPF apps, and otherwise all exceptions end up getting converted to a DispatcherUnhandledException, and all the actual information you want is lost. WPF sucks like that.

  2. As soon as I hit any code that's using dynamic, the debug output log becomes fairly useless. All the useful trace lines that I care about get hidden amongst all the useless RuntimeBinderExceptions

Is there any way I can turn this off, or is the RuntimeBinder unfortunately just built like that?

Thanks, Orion

解决方案

Whenever a property on a dynamic object is resolved, the runtime tries to find a property that is defined at compile time. From DynamicObject doco:

RuntimeBinderException is thrown whenever the runtime cannot find a statically defined property(i.e. what would be a compiler error in 100% statically typed world). From MSDN article

It is interesting that if you use ExpandoObject, you only get one exception when trying to use the property:

dynamic bucket = new ExpandoObject();
bucket.SomeValue = 45;
int value = bucket.SomeValue; //<-- Exception here

Perhaps ExpandoObject could be an alternative? If it's not suitable you'll need to look into implementing IDynamicMetaObjectProvider, which is how ExpandoObject does dynamic dispatch. However, it is not very well documented and MSDN refers you to the DLR CodePlex for more info.

这篇关于处理动态时抛出的很多第一次机会 Microsoft.CSharp.RuntimeBinderExceptions的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-24 05:21