Что-то не так с динамическим ключевым словом в C # 4.0? - PullRequest
50 голосов
/ 21 февраля 2010

При использовании C # 4.0 наблюдается странное поведение:

using System;

class Program {
  public void Baz() { Console.WriteLine("Baz1"); }
  static void CallBaz(dynamic x) { x.Baz(); }

  static void Main(string[] args) {
    dynamic a = new Program();
    dynamic b = new { Baz = new Action(() => Console.WriteLine("Baz2")) };

    CallBaz(a); // ok
    CallBaz(b); // ok
    CallBaz(a); // Unhandled Exception:
    // Microsoft.CSharp.RuntimeBinder.RuntimeBinderException:
    // The name 'Baz' is bound to a method and cannot be used like a property
  }
}

Я использую кандидата на выпуск Visual Studio 2010.

Это ошибка? Если это правда, будет ли это исправлено в Релизе?

Ответы [ 4 ]

32 голосов
/ 22 февраля 2010

Я могу подтвердить, что это действительно ошибка. Краткое описание того, что идет не так, выглядит следующим образом: В CallBaz есть один сайт вызова, который вызывается три раза. Этот CallSite является InvokeMember, потому что это лучшее предположение, которое компилятор может сделать, учитывая синтаксис C #, несмотря на то, что в действительности он может преобразоваться в GetMember, за которым следует Invoke.

Во время второго выполнения места вызова это действительно привязка, которую находит среда выполнения. И поэтому он производит отсрочку для GetMember с последующим вызовом. Ошибка заключается в том, что эта отсрочка не ограничивается должным образом случаем, когда аргумент является анонимным типом. Таким образом, в третьем выполнении отсрочка запускается, и GetMember пытается привязать к Программе, что, конечно, не удается.

Спасибо, что нашли это. Как указывает Эрик, мы находимся здесь на очень поздней стадии, и нам становится все труднее решать проблемы перед отправкой. Но мы также хотим доставить правильный продукт. Я собираюсь сделать все возможное, чтобы решить эту проблему, хотя, возможно, мне это не удастся. Если вы придумали что-нибудь еще, пожалуйста, не стесняйтесь связаться со мной. =)

UPDATE:

Хотя я не могу гарантировать, как будет выглядеть финальная версия VS 2010 и C # 4, когда она выйдет, я могу сказать, что мне удалось продвинуть это исправление. Сегодняшняя релизная сборка ведет себя правильно для вашего кода. За исключением некоторой катастрофы, вы увидите, что это исправлено при выпуске. Еще раз спасибо. Я должен тебе пиво.

11 голосов
/ 22 февраля 2010

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

Просто чтобы установить ожидания: если это ошибка, и она еще не найдена и не исправлена, шансы хорошие, исправление не попадет в финальную версию.

Спасибо, что обратили на это наше внимание!

8 голосов
/ 21 февраля 2010

Это похоже на серьезную ошибку ...

Обратите внимание, что он работает нормально, если вы используете ExpandoObject вместо анонимного типа:

using System;
using System.Dynamic;

class Program {
  public void Baz() { Console.WriteLine("Baz1"); }
  static void CallBaz(dynamic x) { x.Baz(); }

  static void Main(string[] args) {
    dynamic a = new Program();
    dynamic b = new ExpandoObject();
    b.Baz = new Action(() => Console.WriteLine("Baz2"));

    CallBaz(a); // ok
    CallBaz(b); // ok
    CallBaz(a); // ok
  }
}

Так что проблема кажется специфичной для анонимных объектов ...

Очевидно, что во втором вызове CallBaz(a) DLR все еще пытается получить доступ к Baz как свойство, потому что это было свойство анонимного типа. Я подозреваю, что механизм связывания C # выполняет некоторое кэширование разрешения вызовов для повышения производительности, но в этом случае он явно не работает ...

2 голосов
/ 21 февраля 2010

То же самое происходит со мной, я предлагаю вам сообщить об этом здесь .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...