Много шансов Microsoft.CSharp.RuntimeBinderException, возникающих при работе с динамикой - PullRequest
51 голосов
/ 02 июня 2010

У меня есть стандартный класс типа 'динамический словарь' в 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);
    }
}

Теперь я называю это следующим образом:

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

Приложение делает то, что от него ожидают, но выходные данные отладки выглядят так:

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

Любая попытка доступа к динамическому члену, похоже, выводит RuntimeBinderException в журналы отладки. Хотя я знаю, что исключения первого шанса сами по себе не являются проблемой, это вызывает у меня некоторые проблемы:

  1. У меня часто есть отладчик, настроенный на «прерывание по исключениям», так как я пишу приложения WPF, в противном случае все исключения в итоге преобразуются в DispatcherUnhandledException, и вся необходимая информация теряется , WPF такой отстой.

  2. Как только я нажимаю любой код, который использует dynamic, журнал вывода отладки становится довольно бесполезным. Все полезные линии трассировки, о которых я забочусь, прячутся среди всех бесполезных RuntimeBinderException s

Можно ли как-нибудь отключить это, или, к сожалению, RuntimeBinder просто построен таким образом?

Спасибо, Орион

Ответы [ 2 ]

25 голосов
/ 02 июня 2010

Всякий раз, когда свойство динамического объекта разрешается, среда выполнения пытается найти свойство, определенное во время компиляции. Из документа DynamicObject:

Вы также можете добавлять своих участников в классы, производные от DynamicObject учебный класс. Если ваш класс определяет свойства, а также переопределяет TrySetMember метод, динамический Language Runtime (DLR) сначала использует связыватель языка для поиска статического определение свойства в классе. Если такого свойства нет, DLR вызывает метод TrySetMember.

RuntimeBinderException генерируется всякий раз, когда среда выполнения не может найти статически определенное свойство (то есть, что было бы ошибкой компилятора в мире со 100% статической типизацией). От MSDN артикул

... RuntimeBinderException представляет собой неспособность связать в смысле обычная ошибка компилятора ...

Интересно, что если вы используете ExpandoObject, вы получите только одно исключение при попытке использовать свойство:

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

Возможно, ExpandoObject может быть альтернативой? Если это не подходит, вам нужно изучить реализацию IDynamicMetaObjectProvider, как ExpandoObject выполняет динамическую диспетчеризацию. Однако это не очень хорошо задокументировано, и MSDN направляет вас в DLR CodePlex для получения дополнительной информации.

21 голосов
/ 02 июня 2011

Это меня тоже беспокоило. Я добавил исключение в список исключений, чтобы отменить выбор. Просто выполните следующие действия:

  • В меню «Отладка» выберите «Исключения».
  • Нажмите кнопку "Добавить ..." в правом нижнем углу.
  • Выберите «Исключения общего языка во время выполнения» из раскрывающегося списка «Тип».
  • Введите «Microsoft.CSharp.RuntimeBinder.RuntimeBinderException» в качестве имени.
  • Нажмите ОК.
  • Тип исключения теперь появится в списке. Просто отмените выбор.

Мне бы хотелось, чтобы этот параметр можно было сохранить в разных решениях, но я не думаю, что это возможно, поэтому вам придется повторно применять этот параметр в каждом решении.

...