2014-07-15 11 views
5

C# 'da dinamik değişkenleri kullanma ile ilgili sorunlarla karşılaştım. Bu, NancyFx yönlendirme modüllerini kodlarken ortaya çıktı, ancak sorunu aşağıdaki örnekte kaynattım. Orijinal kodda farklı bir istisna aldığım halde, örnek kod hala hatalı olduğuna inandığım bir istisna atar. Burada neler olup bittiğini gören var mı, başkaları da benzer sorunlarla karşılaştı mı? Aşağıdaki mesajlar ilişkili olabilirC# dinamik olarak olası hata?

Not: StackOverflowException when accessing member of generic type via dynamic: .NET/C# framework bug? System.Dynamic bug?

kodu:

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(); 
    } 
} 

istisna: 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

şeklindedir. Bu soruya cevap verildiği gibi görünüyor [here] (http://stackoverflow.com/a/258999/97382). –

+1

http://stackoverflow.com/questions/258988/will-the-dynamic-keyword-in-c4-support-extension-methods adresinin aynı soruyu ele aldığına inanmıyorum. Örnek kod, dinamik olarak bildirilen bir değişken üzerinde bir uzantı yöntemini kullanmaya çalışmaz, bir arabirim türü döndüren bir yöntem sonucunda bunu kullanır. Dolayısıyla, bir uzantı yöntemini yürüten yöntemin her iki sürümünde, uzantı yönteminin uygulandığı tür dinamik değildir. –

+0

Orijinal soruyu sormamın başka bir yolu, bir "var" değişken bildiriminin ne zaman atandığınız değerin türü gibi davranmaması gerektiğidir. –

cevap

5

sorun bunu yaptığında açıkça atanmamış olması Nesne, IDictionary<string,object> bildirgesine, nesne yine dinamik bir tip olacaktır (resimlerde türün çözünürlüğüne bakın).

Eric Lippert'ın dinamik türleri için, çağrı sitesinde mevcut olmayacaktır https://stackoverflow.com/a/5313149/1039903 uzatma yöntemlerinde işaret ettiği gibi:

Jon'un yanıta genişletmek için bu işe yaramazsa nedeni normal çünkü olduğunu, dinamik olmayan kod uzantısı yöntemleri, derleyici tarafından bilinen tüm sınıfların tam bir aramasını yaparak, eşleşen bir uzantı yöntemine sahip statik bir sınıf için çalışır. Arama, ad alanı iç içe geçirme ve her ad alanında kullanılabilir "kullanma" yönergelerine dayanarak sırayla devam eder.

Bu, dinamik bir uzantı yöntemi çağrısı doğru bir şekilde çözümlenebilmesi için, bir şekilde, DLR'nin çalışma zamanında tüm ad alanı yerleştirme ve "kullanma" yönergelerinin kaynak kodunuzda ne olduğunu bilmesi gerektiği anlamına gelir. Tüm bu bilgileri çağrı sitesine şifrelemek için kullanışlı bir mekanizma yoktur. Böyle bir mekanizma icat etmeyi düşündük, ama bunun çok yüksek maliyetli olduğunu ve buna değecek kadar çok zamanlama riski oluşturduğuna karar verdik.

Aslında açık bir beyanı ile karşılaştırıldığında çalışma zamanı sırasında var dictionary içinde çözülürse size göstermek için bir test yöntemine içine kodunuzu yüklendi.

Açık ifadesi:

enter image description here enter image description here

Örtülü beyan

enter image description here enter image description here

Eğer açık bildirim vardır dictionary tipi çözünürlükte bir göz atacak olursak System.Collection.Generic.IDictionary ve yazın örtülü aralık kllanım türü dynamic{System.Collections.Generic.Dictionary}

+0

Hiçbir zaman oynamaktan başka dinamik kelime kullanmıyorum ve bu bilmek için harika bir bilgi. Dinamik olduğunda onu tekrar statik bir türe dönüştürmenin bir yolu yok mu? – TyCobb

+0

İstediğiniz türe atayın veya "as" anahtar sözcüğünü kullanın. (yani 'vari dict = CastDictionary (reallyDictionary) IDictionary ') – wbennett

+0

Ancak, "CastDictionary" zaten bir "IDictionary" döndürüyor. – TyCobb