2009-03-26 37 views
15

Tôi có một lớp Generic như thế:Làm cách nào để tạo một lớp chung từ một chuỗi trong C#?

public class Repository<T> {...} 

Và tôi cần phải dụ rằng với một chuỗi ... Ví dụ:

string _sample = "TypeRepository"; 
var _rep = new Repository<sample>(); 

Làm thế nào tôi có thể làm điều đó? Điều đó thậm chí có thể?

Cảm ơn!

+0

Lưu ý rằng bạn không thể tham chiếu đến Kho lưu trữ trong chương trình của bạn, do đó, loại _rep sẽ phải là 'đối tượng' hoặc một số giao diện chung cho tất cả Kho lưu trữ . –

Trả lời

24

Đây là của tôi 2 cent:

Type genericType = typeof(Repository<>); 
Type[] typeArgs = { Type.GetType("TypeRepository") }; 
Type repositoryType = genericType.MakeGenericType(typeArgs); 

object repository = Activator.CreateInstance(repositoryType); 

Trả lời câu hỏi trong nhận xét.

MethodInfo genericMethod = repositoryType.GetMethod("GetMeSomething"); 
MethidInfo closedMethod = genericMethod.MakeGenericMethod(typeof(Something)); 
closedMethod.Invoke(repository, new[] { "Query String" }); 
+0

Và Làm cách nào tôi có thể truy cập vào các phương thức lưu trữ? – Paul

+2

Giống như cách bạn đã tạo kho lưu trữ cho loại chỉ được biết trong thời gian chạy, sử dụng sự phản chiếu. Bạn muốn sự linh hoạt, bạn cần phải trả tiền cho nó. – alex

+0

Bạn có thể chỉ cho tôi cách thực hiện điều đó không? Cảm ơn! – Paul

-3

Chữ "T" trong lớp Chung là viết tắt của một loại, không phải là một thể hiện của một loại. Vì vậy, nếu bạn muốn kho của bạn để giữ các đối tượng chuỗi, sau đó sử dụng

var _rep = new Repository<string>(); 
+0

Tôi nghĩ bạn đã hiểu sai câu hỏi - chuỗi chứa tên loại. –

16

tiên nhận được đối tượng sử dụng Loại Type.GetType(stringContainingTheGenericTypeArgument)

Sau đó sử dụng typeof(Repository<>).MakeGenericType(theTypeObject) để có được một kiểu generic.

Và cuối cùng sử dụng Activator.CreateInstance

+0

Không phải là câu hỏi thực sự "nên anh ấy"? –

+0

từ chuỗi thành kiểu genertic? Có lẽ. Tuy nhiên, MakeGenericType thường được sử dụng trong các nhà cung cấp LINQ và mã tiêu thụ cây biểu thức khác chẳng hạn.nó là một người trợ giúp tuyệt vời, mặc dù cho mỗi ngày ứng dụng LOB nó không phải là một cái gì đó để lo lắng về khóa học. –

0

Đây là "loại" có thể. Sắp xếp trong đó bạn có thể làm điều đó, nhưng nó là một chút của một hack.

Bạn có 3 tùy chọn:

Nếu bạn biết lớp học của mình ở phía trước, hãy sử dụng câu lệnh chuyển đổi. Về cơ bản như thế này:

switch(str){ 
    case "TypeRepository": return new Repository<TypeRepository>; 
} 

Như một hình thức tiên tiến hơn những điều trên, bạn có thể sử dụng một từ điển thay vì một Hashtable

var factory = new Dictionary<string, Func<object>>(); 
factory.Add("TypeRepository",() => new Repository<TypeRepository>()); 

var theObject = factory["TypeRepository"]() as Repository<TypeRepository>; 

Đối với sự linh hoạt lớn nhất, Bạn có thể sử dụng phản ánh để phù hợp với chuỗi đến các lớp học trong thời gian chạy. Hãy nhận biết rằng sự phản chiếu khá chậm, vì vậy nếu bạn đang làm điều này với bất kỳ loại nào đều đặn, bạn muốn tránh nó. Ví dụ: Dưới đây là một phương thức sử dụng phương thức Frans Bouma's. Chỉ cần thay đổi List<> để Repository<> trong mã của bạn:

public static object MakeList(string typeStr) 
{ 
    var nameSpace = "MyTestApplication" + "."; 

    var objType = Type.GetType(nameSpace + typeStr); // NAMESPACE IS REQUIRED 
    var listType = typeof(List<>).MakeGenericType(objType); 
    return Activator.CreateInstance(listType); 
} 

var listOfThings = MakeList("MyCoolObject") as List<MyCoolObject>; 

Lưu ý: Không có cách nào để tránh thực tế là tất cả các cơ chế này trở object, mà sau đó bạn phải bỏ để loại thích hợp của bạn, thay vì trở về Chỉ cần trả lại gõ mạnh giá trị. Điều này là không thể tránh khỏi, bởi vì bạn không biết loại danh sách cho đến khi chạy, và C# được xây dựng xung quanh việc biết mọi thứ tại thời gian biên dịch (đây là ý nghĩa của mọi người khi họ nói "ngôn ngữ lập trình tĩnh"). Nó sẽ ít đau đớn hơn trong C# 4, nơi bạn sẽ có thể quay trở lại dynamic, điều này sẽ giúp bạn tiết kiệm quá trình truyền.

+0

Cho rằng loại đang được xây dựng bằng cách sử dụng một chuỗi, làm thế nào C# hợp lý kết hợp một loại cụ thể với kết quả? –

0

Generics hoạt động trên các loại, chứ không phải trên các phiên bản. Bạn có thể đọc thêm here.

Âm thanh như bạn chỉ cần thêm một constructor cho lớp của bạn mà mất trong các loại mong muốn và initailizes giá trị:

public class Foo<T> 
{ 
    private T = default(T); 

    public Foo(T initValue) 
    { 
     _val = T; 
    } 
} 
2

Nếu tôi hiểu câu hỏi của bạn một cách chính xác ... Những gì bạn đang cố gắng làm là lấy loại của bạn (Kho lưu trữ <T>) và xây dựng một thực thi cụ thể, chung chung trong thời gian chạy?

Nếu có, hãy xem MakeGenericType. Bạn có thể sử dụng typeof (Repository) và System.Type của đối tượng bạn muốn cho T và xây dựng nó theo cách này. Khi bạn có loại, Activator.CreateInstance sẽ hoạt động cho bạn.

1
Type repType = typeof(Repository <>).MakeGenericType(Type.GetType("System.String")); 
object rep = Assembly.GetAssembly(repType).CreateInstance(repType.FullName); 

Điều này sẽ tạo ra một thể hiện của Repository<string>. Bạn có thể thay thế "System.String" bằng bất kỳ loại nào bạn thích.

2

Giả sử rằng chuỗi của bạn giữ tên của một loại, bạn có thể viết

object _rep = Activator.CreateInstance(typeof(Repository<>).MakeGenericType(Type.GetType(_sample))); 

Tuy nhiên, _rep sẽ là một đối tượng không định kiểu, và bạn sẽ không có cách nào để làm bất cứ điều gì với nó. Vì bạn không biết loại generic class là gì ở thời gian biên dịch, nên không có kiểu nào mà bạn đưa nó vào. (Trừ khi Repository thừa hưởng một lớp không chung chung hoặc thực hiện một giao diện không chung chung)

Bạn có thể giải quyết điều đó bằng cách tạo một lớp cơ sở không chung chung cho Kho lưu trữ và đưa đối tượng vào đó.

Tuy nhiên, tùy thuộc vào tình huống của bạn, bạn có thể muốn tạo Repository một lớp không chung chung.

Nếu Repository là lớp có chứa các lớp khác, tốt nhất nên làm cho nó không chung chung. Bạn có thể làm cho hàm tạo của nó lấy một đối tượng Type và sau đó gọi Type.IsInstanceOfType trên mọi đối tượng bạn thêm để đảm bảo đó là loại phù hợp.

Nếu kho lưu trữ là một bộ sưu tập được phân loại của mọi thứ, tốt nhất là làm cho nó không chung chung và làm cho hàm tạo của nó mất string category.

Nếu bạn muốn được tư vấn cụ thể hơn, vui lòng đăng thêm chi tiết về tình huống của bạn.

+0

Repository của tôi: public class Repository : RepositoryWithTypedId , IRepository {} public class RepositoryWithTypedId : IRepositoryWithTypedId Và tôi không thể thay đổi implementantion rằng ... Vì vậy, là nó không thể? – Paul

+0

Có thể, bằng cách sử dụng dòng mã tôi đã viết ở trên, nhưng nó sẽ rất khó khăn để làm bất cứ điều gì với. Tại sao bạn đang cố thực hiện việc này và bạn đang làm gì với '_rep'? – SLaks

+0

_rep của tôi là một DAO (đối tượng truy cập dữ liệu) ... – Paul

3

Đây là công việc cho từ khóa dynamic đến trong C# 4.0. Có một số hacks đẹp ở đây sẽ giúp bạn có được một thể hiện của đối tượng của bạn, nhưng không có vấn đề gì các phiên bản hiện tại của C# sẽ chỉ biết nó có một object, và nó không thể làm nhiều với một đối tượng bởi chính nó bởi vì C# hiện tại không hỗ trợ kết buộc muộn. Bạn cần ít nhất có thể đưa nó vào một loại đã biết để làm bất cứ điều gì với nó. Cuối cùng, bạn phải biết loại bạn cần tại thời điểm biên dịch hoặc bạn không may mắn.

Bây giờ, nếu bạn có thể hạn chế lớp lưu trữ của mình thành các loại triển khai một số giao diện đã biết, bạn đang ở trong một hình dạng tốt hơn nhiều.

+0

Vì vậy, tôi không có giải pháp cho vấn đề của mình ... – Paul

+0

Không, và quan điểm của tôi là bạn sẽ không nhận được một cái thực sự hoạt động trước khi C# 4 xuất hiện trừ khi bạn có thể nghĩ lại kiến ​​trúc của mình. –

+2

Nếu bạn chia sẻ những gì bạn định làm với các đối tượng kho lưu trữ này, chúng tôi có thể giúp bạn với một thiết kế hoạt động tốt hơn. –

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