2014-07-15 13 views
5

Tôi đã gặp sự cố với việc sử dụng các biến động trong C#. Điều này phát sinh khi mã hóa các mô-đun định tuyến NancyFx, nhưng tôi đã đun sôi vấn đề xuống ví dụ dưới đây. Trong khi tôi nhận được một ngoại lệ khác trong mã ban đầu, mã ví dụ vẫn ném một ngoại lệ mà tôi tin là sai. Có ai nhìn thấy những gì đang xảy ra ở đây, hoặc có những người khác gặp phải vấn đề tương tự?Lỗi có thể xảy ra trong C# động?

Lưu ý rằng bài viết sau đây có thể liên quan: StackOverflowException when accessing member of generic type via dynamic: .NET/C# framework bug? System.Dynamic bug?

Mã:

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

Trường hợp ngoại lệ: 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

Dường như câu hỏi này được trả lời [ở đây] (http://stackoverflow.com/a/258999/97382). –

+1

Tôi không tin rằng http://stackoverflow.com/questions/258988/will-the-dynamic-keyword-in-c4-support-extension-methods giải quyết cùng một câu hỏi. Mã ví dụ không cố gắng sử dụng một phương thức mở rộng trên một biến được khai báo là động, nó sử dụng nó trên kết quả của một phương thức trả về một kiểu giao diện. Vì vậy, trong cả hai phiên bản của phương thức thực thi một phương thức mở rộng, kiểu mà phương thức mở rộng áp dụng không phải là động. –

+0

Một cách khác tôi có thể hỏi câu hỏi ban đầu là khi nào một khai báo biến 'var' không hoạt động như kiểu giá trị mà bạn gán cho nó? –

Trả lời

5

Vấn đề là khi bạn làm không được gán một cách rõ ràng đối tượng để khai báo IDictionary<string,object>, đối tượng sẽ vẫn là loại động (xem độ phân giải loại trong hình ảnh).

Như Eric Lippert chỉ ra trong https://stackoverflow.com/a/5313149/1039903 phương pháp khuyến nông sẽ không có sẵn tại địa điểm cuộc gọi, với nhiều loại động:

Để mở rộng về câu trả lời của Jon, lý do này không hoạt động là bởi vì trong thông thường, các phương thức mở rộng mã không động hoạt động bằng cách thực hiện tìm kiếm đầy đủ tất cả các lớp được biết tới trình biên dịch cho một lớp tĩnh có một phương thức mở rộng phù hợp. Tìm kiếm theo thứ tự dựa trên không gian tên lồng và các chỉ thị "sử dụng" có sẵn trong mỗi không gian tên.

Điều đó có nghĩa là để có được lời gọi phương thức mở rộng động được giải quyết chính xác, bằng cách nào đó DLR phải biết khi chạy tất cả các dấu cách không gian tên và chỉ thị "đang sử dụng" trong mã nguồn của bạn. Chúng tôi không có cơ chế để mã hóa tất cả thông tin đó vào trang web cuộc gọi. Chúng tôi xem xét việc phát minh ra một cơ chế như vậy, nhưng quyết định rằng nó là chi phí quá cao và đã tạo ra quá nhiều rủi ro về lịch trình để có giá trị.

Tôi đã tải mã của bạn thành phương pháp thử để hiển thị cho bạn những gì thực sự được giải quyết trong var dictionary trong thời gian chạy so với khai báo rõ ràng.

khai Explicit:

enter image description here enter image description here

khai Implicit

enter image description here enter image description here

Nếu bạn có một cái nhìn tại Type độ phân giải dictionary tuyên bố rõ ràng có kiểu System.Collection.Generic.IDictionary và -tập tin ngầm ấu trùng có loại dynamic{System.Collections.Generic.Dictionary}

+0

Tôi chưa bao giờ sử dụng từ khóa 'động' khác ngoài việc chơi xung quanh và đây là thông tin tuyệt vời để biết. Không có cách nào để chuyển đổi nó trở lại một loại tĩnh khi nó là động? – TyCobb

+0

Gán nó cho loại mong muốn hoặc sử dụng từ khóa 'as'. (ví dụ 'var dict = CastDictionary (actualDictionary) là IDictionary ') – wbennett

+0

Nhưng, 'CastDictionary' của nó đã trả về một' IDictionary'. – TyCobb

Các vấn đề liên quan