2011-12-11 32 views
35

Tôi có một hàm trả về kiểu ẩn danh mà tôi muốn kiểm tra trong bộ điều khiển MVC của mình.Đúc kiểu ẩn danh thành động

public JsonResult Foo() 
{ 
    var data = new 
        { 
         details = "something", 
         more = "More" 
        }; 
    return Json(data); 
} 

Tôi muốn xác minh dữ liệu tôi nhận được từ hàm Foo, Điều tôi đang làm bây giờ là lấy kiểu dữ liệu và nhận giá trị thuộc tính của nó với sự phản ánh.

[Test] 
public void TestOne() 
{ 
    var data = _controller.Foo().Data; 
    var details = data.GetType().GetProperty("details").GetValue(data, null); 
    var more = data.GetType().GetProperty("more").GetValue(data, null); 

    Assert.AreEquals("something", details); 
    Assert.AreEquals("More", more); 
} 

Có cách nào đơn giản tương tự như điều này để kiểm tra các thuộc tính ẩn danh không?

[Test] 
public void TestTwo() 
{ 
    var data = (dynamic) _controller.Foo().Data; 
    var details = data.details; // RunTimeBinderException object does not contain definition for details 
    var more = data.more; 

    Assert.AreEquals("something", details); 
    Assert.AreEquals("More", more); 
} 
+7

Do đây là để thử nghiệm đơn vị, bạn có thể sử dụng 'InternalsVisibleTo'. Xem [Anonymous Types là Internal, C# 4.0 Dynamic Beware!] (Http://www.heartysoft.com/anonymous-types-c-sharp-4-dynamic) Nhờ @MarcGravell để chỉ ra rằng các đối tượng ẩn danh là 'internal' ! – TrueWill

+0

+1 cho InternalsVisibleĐể đề xuất. Làm việc như một say mê. –

Trả lời

34

đối tượng Anonymous là internal, có nghĩa là các thành viên của họ đang rất hạn chế bên ngoài lắp ráp rằng tuyên bố chúng. dynamic tôn trọng trợ năng, do đó giả vờ không thể xem các thành viên đó. Nếu các trang web gọi là trong cùng một hội đồng, tôi hy vọng nó sẽ làm việc.

Mã phản chiếu của bạn tôn trọng các thành viên thành viên, nhưng bỏ qua khả năng truy cập của loại - do đó nó hoạt động.

Tóm lại: không.

+2

@gdoron tại sao phải không? Dù sao thì nó vẫn là một đối tượng. Nó không phơi bày nhiều thứ khác. ToString(), Equals(), GetHashCode(), vv sẽ vẫn hoạt động thông qua động. Nó chỉ không thêm bất cứ điều gì khác có thể nhìn thấy. –

6

Loại ẩn danh là loại tĩnh thông thường trong .NET, chỉ cần bạn không đặt tên cho nó (trình biên dịch). Đó là lý do tại sao truyền nó đến dynamic sẽ không hoạt động. Tuy nhiên, nếu bạn có quyền kiểm soát trên Foo(), bạn có thể tạo và trả lại đối tượng dynamic thay vì ẩn danh và sau đó mã của bạn sẽ hoạt động. Điều này sẽ làm các trick:

dynamic JsonResult Foo() { 
    dynamic data = new ExpandoObject(); 
    data.details = "something"; 
    data.mode = "More"; 
    return Json(data); 
} 
+0

.Data là "đối tượng". Có rất ít sự khác biệt giữa "đối tượng" và "năng động", ngoại trừ người tiêu dùng (đó là nơi mà nó được vui vẻ). Tôi không tin rằng thay đổi giữa "đối tượng" và "năng động" (và sau đó trở lại năng động) sẽ làm nhiều ở đây. –

+0

@MarcGravell Tôi đã thêm mã để làm rõ ý tôi là gì * trả về động * (Tôi thực sự có nghĩa là "xây dựng một đối tượng động và trả về", không đơn giản "thay đổi kiểu trả về thành động"). Cảm ơn vì đã bắt nó - bản chỉnh sửa ban đầu thực sự không rõ ràng. – dasblinkenlight

+1

Điều chính mà làm cho công việc này là: ExpandoObject là công khai không nội bộ (và tất nhiên thực hiện các giao diện IDynamicBlahBlahBlah như một tuyên bố công khai). Tuy nhiên, nó sẽ nhắc câu hỏi quan trọng: lớp JSON có giống ExpandoObject không? (nó * có thể * do việc sử dụng IDictionary). Điều này cũng có nghĩa là chúng tôi không còn sử dụng loại anon (câu hỏi) –

22

Blog này có câu trả lời công việc: http://blog.jorgef.net/2011/06/converting-any-object-to-dynamic.html - Cảm ơn @ Jorge-Fioranelli.

public static class DynamicExtensions { 
    public static dynamic ToDynamic(this object value) { 
     IDictionary<string, object> expando = new ExpandoObject(); 

     foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(value.GetType())) 
      expando.Add(property.Name, property.GetValue(value)); 

     return expando as ExpandoObject; 
    } 
} 
4

Theo đề nghị của @TrueWill và @Marc Gravell, ai cũng gọi this blog post

Do đây là để thử nghiệm đơn vị, bạn có thể sử dụng InternalsVisibleTo. Xem các kiểu ẩn danh là Internal, C# 4.0 Dynamic Beware! Nhờ @MarcGravell chỉ ra rằng các đối tượng ẩn danh là nội bộ!

Bottom line: Thiết lập ánh xạ [assembly: InternalsVisibleTo("foo")] nếu bạn muốn chia sẻ một đối tượng ẩn danh từ một assembly này đến một assembly khác. Trong trường hợp OP, nó sẽ là một vấn đề của thiết lập này trong dự án điều khiển MVC, đề cập đến các dự án thử nghiệm . Trong trường hợp cụ thể của tôi, cách khác xung quanh (kể từ khi tôi đang đi qua một đối tượng vô danh từ dự án thử nghiệm của tôi vào dự án "mã sản xuất").

Cách dễ nhất trong "dự án khác" để có thể sử dụng nó chắc chắn sẽ truyền tới dynamic và sau đó chỉ sử dụng các thuộc tính như bình thường. Nó hoạt động, không có vấn đề gì.

Vì vậy, điểm mấu chốt: Tôi cảm thấy rằng câu trả lời của Marc Gravell hơi không chính xác; điều này có thể được thực hiện rõ ràng
(iff các dự án được đề cập có thể sửa đổi được bởi bạn, vì vậy bạn có thể thiết lập Bản đồ InternalsVisibleTo tương ứng và điều này không gây ra vấn đề với bất kỳ lý do nào khác).

1

Bạn có thể sử dụng NewtonSoft hoặc Asp.thư viện MVC ròng:

var data = Json.Decode(Json.Encode(_controller.Foo().Data));

var data=JsonConvert.DeserializeObject<Dictionary<string,object>>(JsonConvert.SerializeObject((_controller.Foo().Data))

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