2012-06-27 42 views
5

tôi là tạo ra các trường hợp của một kiểu generic sử dụng phản ánh:Đúc trường hợp loại generic tạo sử dụng Reflection

public interface IModelBuilder<TModel> 
{ 
    TModel BuildModel(); 
} 

public class MyModel 
{ 
    public string Name { get; set; } 
} 

public class MyModelBuilder : IModelBuilder<MyModel> 
{ 
    public MyModel BuildModel() 
    { 
     throw new NotImplementedException(); 
    } 
} 

Khi chạy tất cả chúng ta đều biết là Loại mô hình ví dụ MyModel. Tôi có thể tìm thấy trường hợp của những người xây dựng mô hình liên quan như sau:

var modelBuilders = from t in Assembly.GetExecutingAssembly().GetTypes() 
       from i in t.GetInterfaces() 
       where i.IsGenericType 
         && i.GetGenericTypeDefinition() == typeof(IModelBuilder<>) 
         && i.GetGenericArguments()[0] == modelType 
       select t; 

var builder = Activator.CreateInstance(modelBuilders.First()); 

Nhưng tôi không chắc chắn làm thế nào tôi có thể sau đó cast dụ như IModelBuilder<TModel> vì vậy tôi có thể gọi và làm việc với các kết quả của BuildModel().

Trả lời

14

modelType chỉ là một trường hợp Type, bạn không thể tự động làm điều đó vì không có API không chung chung. Nhiều tùy chọn:

1: sử dụng phản chiếu, ví dụ (chưa được kiểm tra)

object builder = Activator.CreateInstance(...); 
var model=builder.GetType().GetMethod("BuildModel").Invoke(builder,null); 

2: gian lận với dynamic:

dynamic builder = Activator.CreateInstance(...); 
var model = builder.BuildModel(); 

3: thực hiện một phiên bản không phải chung của IModelBuilder, và sử dụng rằng

Lưu ý rằng 1 & 2 dựa trên triển khai công khai của inte rface, và sẽ thất bại cho một (hoàn toàn hợp pháp) thực hiện giao diện rõ ràng. Đối với "1", bạn có thể khắc phục điều này qua:

var model = typeof(IModelBuilder<>).MakeGenericType(modelType) 
     .GetMethod("BuildModel").Invoke(builder); 

Một lựa chọn lén lút cuối cùng là lật từ một phương pháp không chung vào một phương pháp chung chung, do bên trong phương pháp chung chung, bạn có thể sử dụng tất cả các thành viên trực tiếp. Có một cách lười biếng để thực hiện điều đó qua dynamic:

interface ISneaky<T> 
{ 
    T Foo { get; } 
} 
class Sneaky<T> : ISneaky<T> 
{ 
    T ISneaky<T>.Foo { get { return default(T); } } 
} 
class Program 
{ 
    static void Main() 
    { 
     Execute(typeof(int)); 
    } 
    static void Execute(Type t) 
    { 
     dynamic obj = Activator.CreateInstance(
      typeof(Sneaky<>).MakeGenericType(t)); 
     // crafy hack to flip from non-generic code into generic code: 
     Evil(obj); 
    } 
    static void Evil<T>(ISneaky<T> sneaky) 
    { // in here, life is simple; no more reflection 
     Console.WriteLine("{0}: {1}", typeof(T).Name, sneaky.Foo); 
    } 
} 
+0

Tôi có cảm giác đây là trường hợp. Tôi nghĩ rằng tùy chọn 2 sẽ làm việc tốt nhất cho tôi vì tôi cần phải làm việc với các thuộc tính trên mô hình đã được tạo ra. –

+0

@Ben nếu bạn cần thực hiện một số lượng công việc không nhỏ, bạn cũng có thể * làm điều này với một phương thức chung, rằng bạn * gọi qua phản xạ *, tức là trong phương thức chung của '' nó là 'IModelBuilder '. Bạn có muốn một ví dụ về điều đó không? –

+2

đẹp! Và rất lén lút :) –

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