Lots of first chance Microsoft.CSharp.RuntimeBinderExceptions thrown when dealing with dynamics
C#ExceptionDynamicC# Problem Overview
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:
-
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. -
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 uselessRuntimeBinderException
s
Is there any way I can turn this off, or is the RuntimeBinder
unfortunately just built like that?
Thanks, Orion
C# Solutions
Solution 1 - C#
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:
> You can also add your own members to > classes derived from the DynamicObject > class. If your class defines > properties and also overrides the > TrySetMember method, the dynamic > language runtime (DLR) first uses the > language binder to look for a static > definition of a property in the class. > If there is no such property, the DLR > calls the TrySetMember method.
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
> ...RuntimeBinderException represents a > failure to bind in the sense of a > usual compiler error...
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.
Solution 2 - C#
This was bothering me, too. I added the exception to the exceptions list so that I could deselect it. Just follow these steps:
- From the Debug menu, select Exceptions.
- Click the "Add..." button on the bottom right.
- Choose "Common Language Runtime Exceptions" from the Type dropdown.
- Type "Microsoft.CSharp.RuntimeBinder.RuntimeBinderException" as the name.
- Click OK.
- The exception type will now appear on the list. Just deselect it.
I wish this setting could be saved across solutions, but I don't think it can, so you'll have to reapply this setting on every solution.