2009-10-10 26 views
14

phép nói rằng tôi có lớp học nàyđộng thêm các mục vào một danh sách <T> qua phản ánh

class Child { 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
} 

class Container { 
    public List<Child> { get; set; } 
} 

Tôi đang làm việc trên một deserializer các loại và tôi muốn để có thể tạo ra và đưa vào danh sách Child từ dữ liệu được truy xuất. Tôi đã nhận được này xa (tôi đã cắt bỏ rất nhiều xử lý với nhiều loại khác ví dụ này để nó không cần thiết "iffy" nhưng trần với tôi):

var props = typeof(Container).GetProperties(); 

foreach (var prop in props) { 
    var type = prop.PropertyType; 
    var name = prop.Name; 

    if (type.IsGenericType) { 
     var t = type.GetGenericArguments()[0]; 

     if (type == typeof(List<>)) { 
      var list = Activator.CreateInstance(type); 
      var elements = GetElements(); 

      foreach (var element in elements) { 
       var item = Activator.CreateInstance(t); 
       Map(item, element); 

       // ??? how do I do list.Add(item) here? 
      } 

      prop.SetValue(x, list, null); // x is an instance of Container 

     } 
    } 
} 

tôi không thể tìm ra cách để đúc list về cơ bản List<t.GetType()> để tôi có thể truy cập phương thức thêm và thêm mục.

Trả lời

19

Tôi muốn nói bạn nên bỏ xuống System.Collections.IList và gọi trực tiếp phương thức Thêm. Ưu điểm: đơn giản, không phản ánh xấu xí. Nhược điểm: gây boxing cho Danh sách chứa các loại giá trị.

+0

Tôi thích ý tưởng đó. –

17

Điều này sẽ hoạt động trừ khi tôi thực sự thiếu thứ gì đó.

Bên ngoài của vòng lặp

var add = type.GetMethod("Add"); 

Bên trong vòng lặp

add.Invoke(list, new[] { item }); 
+0

Đây là câu trả lời hay và tôi đánh giá cao câu trả lời của bạn để +1. tác phẩm của bobbymcr mặc dù và không sử dụng sự phản chiếu vì vậy tôi sẽ làm điều đó. Cảm ơn một lần nữa. –

1

Bạn cần phải gọi type.MakeGenericType(type.GetGenericArguments()), mà sẽ trả lại đúng đóng kiểu chung chung. Sau đó, bạn sẽ cần gọi một cách phản ánh phương thức Add. Mã nên tìm kiếm một cái gì đó như thế này:

Type listType = type.MakeGenericType(type.GetGenericArguments()); 
    MethodInfo addMethod = listType.GetMethod("Add"); 
    addMethod.Invoke(instance, new object[] { ... }); 

Tôi không chắc chắn những gì bạn sẽ sử dụng như instance, nhưng đây là đối tượng thực tế mà trên đó phương pháp này sẽ được gọi.

Câu hỏi hay hơn là tại sao bạn lại cố gắng làm điều này? Các.NET Framework đã bao gồm serializers biết làm thế nào để làm tất cả các loại công việc. Nếu bạn có thể, bạn nên sử dụng một trong những thay vì cố gắng "cuộn của riêng bạn".

+0

Tôi biết ai đó sẽ hỏi "tại sao?" XmlSerializer có một số hạn chế (không hỗ trợ Danh sách đáng chú ý nhất) và các tùy chọn khác mà tôi khám phá quá chi tiết cho dự án này (sẽ là một khung, vì vậy nếu nó hoạt động ở mức thấp hơn một chút, thì tốt với tôi) . Về cơ bản để đạt được sự đơn giản tôi đang tìm kiếm, tôi phải cuộn của riêng tôi. –

+0

@ John Sheehan: Tại sao dữ liệu nối tiếp được nối tiếp/quan trọng với bạn? Có serializers khác có sẵn hơn là chỉ XmlSerializer, chẳng hạn như serializer hợp đồng dữ liệu WCF. Nó có thể dễ dàng được sử dụng và hỗ trợ 'List '. Có, nó có thể tạo ra một số XML trông xấu xí, nhưng nói chung không quan trọng. –

+0

Tôi không cần serializing, chỉ deserializing và tôi không muốn sử dụng bất kỳ thuộc tính. –

0

đây là những gì tôi làm

var genericType = _primaryType.GetGenericArguments().First(); 
    var type = typeof(List<>).MakeGenericType(genericType); 
    IList o = (IList)Activator.CreateInstance(type); 
    o.Add(x) 
Các vấn đề liên quan