2012-05-22 16 views
6

Tôi hiện đang sử dụng Generics để tạo một số phương thức động, như tạo đối tượng và điền các thuộc tính với các giá trị.Tạo biến chung từ một loại - Cách thực hiện? Hoặc sử dụng Activator.CreateInstance() với thuộc tính {} thay vì tham số()?

Có cách nào để "động" tạo Generic mà không biết loại không? Ví dụ:

List<String> = new List<String>() 

là một cách predefinied, nhưng

List<(object.GetType())> = new List<(object.GetType()>() 

không đang làm việc ... Nhưng có thể nó?

Đây không phải đang làm việc (Có một cách tiếp cận tương tự mà làm việc?)

public T CreateObject<T>(Hashtable values) 
    { 
     // If it has parameterless constructor (I check this beforehand) 
     T obj = (T)Activator.CreateInstance(typeof(T)); 

     foreach (System.Reflection.PropertyInfo p in typeof(T).GetProperties()) 
     { 
      // Specifically this doesn't work 
      var propertyValue = (p.PropertyType)values[p.Name]; 
      // Should work if T2 is generic 
      // var propertyValue = (T2)values[p.Name]; 

      obj.GetType().GetProperty(p.Name).SetValue(obj, propertyValue, null); 
     } 
    } 

Vì vậy, trong ngắn hạn: làm thế nào để có một "Type" và tạo ra một đối tượng từ đó mà không sử dụng Generics? Tôi đã chỉ sử dụng Generics trong các phương pháp cho đến nay, nhưng nó có thể sử dụng cùng một cách trên các biến? Tôi phải xác định một Generic (T) trước khi phương pháp, vì vậy tôi có thể làm tương tự trên các biến trước khi "tạo" chúng?

... hoặc cách sử dụng "Activator" để tạo đối tượng có Thuộc tính thay vì Tham số. Cũng giống như bạn làm ở đây:

// Với các thông số đánh giá cao

Test t = new Test("Argument1", Argument2); 

// Với tính

Test t = new Test { Argument1 = "Hello", Argument2 = 123 }; 

Trả lời

13

Bạn có thể sử dụng MakeGenericType:

Type openListType = typeof(List<>); 
Type genericListType = openListType.MakeGenericType(obj.GetType()); 
object instance = Activator.CreateInstance(genericListType); 
+0

Tôi không muốn sử dụng "Danh sách" trong trường hợp này, nó phải là bất kỳ đối tượng nào. "Loại openListType = typeof (loại không xác định);" – Deukalion

+0

Tôi không thấy câu trả lời này giải quyết OP như thế nào "sử dụng Activator.CreateInstance() với thuộc tính {} thay vì tham số()?" – Avishek

1

Khi bạn sử dụng các đối tượng khởi tạo, nó chỉ sử dụng một constructor mặc định (không có tham số), sau đó thiết lập các thuộc tính riêng lẻ sau khi đối tượng được xây dựng.

Đoạn mã ở trên gần - nhưng var sẽ không hoạt động ở đây, vì đó chỉ là một sự loại bỏ kiểu thời gian biên dịch. Kể từ khi bạn đã sử dụng phản chiếu, bạn chỉ có thể sử dụng System.Object:

object propertyValue = values[p.Name]; 

Cuộc gọi SetValue sẽ làm việc tốt với System.Object.

+0

Vì vậy, làm thế nào tôi có thể sử dụng Activator.CreateInstance với "đối tượng initializer "làm đối số? Tôi nhận được thông báo lỗi "Không có hàm tạo tham số nào được xác định cho đối tượng này". Các loại thuộc tính mà tôi cố gắng thêm giá trị là: Chuỗi, Đôi, enum, bool. Loại không thành công là "Chuỗi". Nó không có constructor parameterless vì vậy tôi không thể tạo ra một String và thêm giá trị cho nó, nhưng làm thế nào có thể được kể từ khi tôi có thể xác định: String str; hoặc String str = "Đây là một chuỗi"; – Deukalion

+0

@Deukalion Loại bạn đang tạo không có hàm tạo tham số - vì vậy bạn không thể sử dụng kỹ thuật này với nó ... –

+0

Cú pháp 'Chuỗi str =" Foo ";' là một tính năng ngôn ngữ C#, không phải là Tính năng CLR. –

5

Bạn có thể sử dụng phương pháp MakeGenericType để có được những loại chung cho một đối số kiểu đặc biệt:

var myObjListType = typeof(List<>).MakeGenericType(myObject.GetType()); 
var myObj = Activator.CreateInstance(myObjListType); 
// MyObj will be an Object variable whose instance is a List<type of myObject> 
+0

Nhưng nói đối tượng tôi tạo ra là một "Chuỗi, boolean, int, float ..." không nhất thiết phải là một lớp. Nếu sau đó tôi cần đặt giá trị cho nó trước khi đặt thuộc tính đối tượng thành giá trị. – Deukalion

+0

Đối với các loại giá trị bạn không cần đặt giá trị - chúng tự động có mặc định hợp lệ. Ví dụ, một trường kiểu 'bool' không cần phải được khởi tạo thành' false', bởi vì điều đó xảy ra tự động. Đối với các chuỗi, chúng bắt đầu rỗng. Nếu bạn muốn làm cho chúng có giá trị khác, như "Fred", bạn cần đặt giá trị của chúng thành "Fred". Không phải 'Person.FirstName = new String (" Fred ");', thấy không? –