Подтвердить что ты не робот

Что-то не так с ключевым словом dynamic в С# 4.0?

В динамическом использовании С# 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.

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

4b9b3361

Ответ 1

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

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

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

UPDATE:

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

Ответ 2

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

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

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

Ответ 3

Это выглядит как серьезная ошибка...

Обратите внимание, что он отлично работает, если вы используете 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 как к свойству, поскольку это свойство было анонимным. Я подозреваю, что связующее С# делает некоторое кэширование разрешения вызова для лучшей производительности, но в этом случае оно явно сломалось...

Ответ 4

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