2014-07-15 6 views
5

У меня возникли проблемы с использованием динамических переменных в C#. Это возникло при кодировании модулей маршрутизации NancyFx, но я рассмотрел проблему ниже. Хотя в исходном коде я получил другое исключение, код примера по-прежнему вызывает исключение, которое, по моему мнению, ошибочно. Кто-нибудь видит, что здесь происходит, или другие сталкиваются с подобными проблемами?Возможная ошибка в C# dynamic?

Обратите внимание, что могут быть связаны следующие сообщения: StackOverflowException when accessing member of generic type via dynamic: .NET/C# framework bug? System.Dynamic bug?

Код:

class Program 
{ 
    static void Main(string[] args) 
    { 
     var dictionary = new Dictionary<string, object>(); 
     dictionary.Add("number", 12); 
     var result = MethodUsesExplicitDeclaration(dictionary); 
     var result2 = MethodUsesImplicitDeclaration(dictionary); 
    } 

    static dynamic MethodUsesExplicitDeclaration(dynamic reallyDictionary) 
    { 
     // this works, ostensibly because the local variable is explicitly declared 
     IDictionary<string, object> dictionary = CastDictionary(reallyDictionary); 
     return dictionary.Get<int>("number"); 
    } 

    static dynamic MethodUsesImplicitDeclaration(dynamic reallyDictionary) 
    { 
     // this throws an exception, and the only difference is 
     // that the variable declaration is implicit 
     var dictionary = CastDictionary(reallyDictionary); 
     return dictionary.Get<int>("number"); 
    } 

    static IDictionary<string, object> CastDictionary(dynamic arg) 
    { 
     return arg as IDictionary<string, object>; 
    } 
} 

static class Extensions 
{ 
    public static T Get<T>(this IDictionary<string, object> dictionary, string key) 
    { 
     var value = dictionary[key]; 
     if (value is T) 
      return (T)value; 
     throw new InvalidOperationException(); 
    } 
} 

Исключение: Microsoft.CSharp.RuntimeBinder.RuntimeBinderException was unhandled HResult=-2146233088 Message='System.Collections.Generic.Dictionary<string,object>' does not contain a definition for 'Get' Source=Anonymously Hosted DynamicMethods Assembly StackTrace: at CallSite.Target(Closure , CallSite , Object , String) at System.Dynamic.UpdateDelegates.UpdateAndExecute2[T0,T1,TRet](CallSite site, T0 arg0, T1 arg1) at DynamicBug.Program.MethodUsesImplicitDeclaration(Object reallyDictionary) in c:\TFS\UnreleasedCode\POC\DynamicBug\DynamicBug\Program.cs:line 28 at DynamicBug.Program.Main(String[] args) in c:\TFS\UnreleasedCode\POC\DynamicBug\DynamicBug\Program.cs:line 16 InnerException:

+1

Похоже, что на этот вопрос будет дан ответ [здесь] (http://stackoverflow.com/a/258999/97382). –

+1

Я не считаю, что http://stackoverflow.com/questions/258988/will-the-dynamic-keyword-in-c4-support-extension-methods обращается к одному и тому же вопросу. Код примера не пытается использовать метод расширения для переменной, объявленной как динамический, она использует ее в результате метода, который возвращает тип интерфейса. Поэтому в обеих версиях метода, который выполняет метод расширения, тип, к которому применяется метод расширения, не является динамическим. –

+0

Другой способ, которым я мог задать исходный вопрос, - это когда объявление переменной var var должно вести себя как тип значения, которое вы ему назначили? –

ответ

5

Проблема заключается в том, что, когда вы явно не назначены объект к объявлению IDictionary<string,object>, объект по-прежнему будет иметь динамический тип (см. разрешение типа изображений).

Как Эрик Липперт указывает на https://stackoverflow.com/a/5313149/1039903 методы расширения не будут доступны на месте вызова, для динамических типов:

Чтобы расширить ответ Джона, причина этого не работает, потому что в регулярных, нединамические методы расширения кода работают, выполняя полный поиск всех классов, известных компилятору для статического класса, который имеет метод расширения, который соответствует. Поиск выполняется в порядке, основанном на вложенности пространств имен и доступных «используемых» директив в каждом пространстве имен.

Это означает, что для того, чтобы вызвать вызов динамического метода расширения, было правильно разрешено, так как DLR во время выполнения должна знать, что все вложения имен и «используемые» директивы были в вашем исходном коде. У нас нет механизма для кодирования всей этой информации на сайт вызова. Мы считали, что изобретаем такой механизм, но решили, что он слишком дорогостоящий, и он слишком много рискует, чтобы его стоило.

Я загрузил ваш код в тестовый метод, чтобы показать вам, что на самом деле разрешено в var dictionary во время выполнения по сравнению с явным объявлением.

Явное объявление:

enter image description here enter image description here

неявное объявление

enter image description here enter image description here

Если вы посмотрите на разрешение Цель dictionary явное объявление имеет тип System.Collection.Generic.IDictionary и тому неявный dec laration имеет тип dynamic{System.Collections.Generic.Dictionary}

+0

Я никогда не использовал ключевое слово 'dynamic', кроме игры, и это отличная информация. Невозможно ли преобразовать его обратно в статический тип, если он является динамическим? – TyCobb

+0

Назначьте его желаемому типу или используйте ключевое слово 'as'. (т. е. 'var dict = CastDictionary (reallyDictionary) как IDictionary ') – wbennett

+0

Но его 'CastDictionary' уже возвращает' IDictionary'. – TyCobb

Смежные вопросы