2012-08-23 24 views
5

Tôi đang gặp vấn đề về generics trong khi làm việc với bộ xử lý Dependency Injection chung (một Service Locator).Làm thế nào bạn có thể bỏ T vào một lớp để khớp với ràng buộc "nơi T: lớp"?

Sửa 1 (cho rõ ràng)

Được rồi vì vậy tôi thực sự sử dụng SimpleInjector như một resolver DI và nó có hạn chế lớp trên đó là phương pháp getInstance, vì vậy đây là một số mã hoàn chỉnh hơn:

public T GetInstance<T>() where T : class 
    { 
    try 
    { 
     // works 
     return _container.GetInstance<T>(); 
    } 
    catch(ActivationException aEx) 
    { 
     return default(T); 
    } 
    } 

    public T GetInstance<T>() 
    { 
    try 
    { 
     if(typeof(T).IsClass) 
     { 
      // does not work, T is not a reference type 
      return _container.GetInstance<T>(); 
     } 
    } 
    catch(ActivationException aEx) 
    { 
     return default(T); 
    } 
    } 

chỉnh sửa 2 - mã cuối cùng vì nó trông lạ trong ý kiến:

public T GetInstance<T>() 
    { 
    try 
    { 
     if(typeof(T).IsClass) 
     { 
      return (T) _container.GetInstance(typeof(T)); 
     } 
    } 
    catch(ActivationException aEx) 
    { 
     return default(T); 
    } 
    } 
+5

Có lẽ nếu chúng ta biết thêm về lý do tại sao bạn quan tâm trong việc này, ngoài một ví dụ rỗng trở về ...? Có thể là một cách tốt hơn để cấu trúc nó. –

+0

Vui lòng xem chỉnh sửa 1 để biết lý do tôi muốn thực hiện việc này. – Laurence

Trả lời

1

Bạn có thể sử dụng một phương thức trợ giúp khác? vui lòng tìm lớp kiểm tra bên dưới

public class Test 
{ 
    public T GetInstance<T>() where T : class 
    { 
    return (T)GetInstance(typeof(T)); 
    } 

    private object GetInstance(Type type) 
    { 
    return Activator.CreateInstance(type); 
    } 

    public T GetEvenMoreGenericInstance<T>() 
    { 
    if(!typeof(T).IsValueType) 
    { 
     return (T)GetInstance(typeof(T)); 
    } 
    return default(T); 
    } 
} 
+0

Điều đó thực sự hiệu quả, cảm ơn. Tôi quên về đúc để T: 'công T getInstance () { thử { if (typeof (T) .IsClass) { return (T) _container.GetInstance (typeof (T)); } } bắt (ActivationException aEx) { trả về mặc định (T); } } ' – Laurence

1

Câu trả lời ngắn gọn là bạn không thể làm điều này, ít nhất là không trực tiếp. Trình biên dịch sẽ phải làm rất nhiều công việc để đảm bảo rằng T sẽ luôn luôn là một lớp trong tình huống của bạn, vì vậy nó sẽ không cho phép bạn truyền nó như một tham số kiểu generic mà không áp dụng cùng một ràng buộc kiểu cho GetEvenMoreGenericInstance.

Bạn có thể thực hiện điều này thông qua sự phản ánh hoặc tạo một quá tải không chung chung của GetInstance lấy một tham số kiểu. Tôi muốn giới thiệu tùy chọn Loại tham số hoặc cấu trúc lại mã của bạn hoàn toàn để loại bỏ nhu cầu gọi phương thức này.

0

Bạn có thể sử dụng phản ánh để tìm biến thể GetInstance, sau đó gọi một biến thể phù hợp.

Ví dụ sau đây làm cho các cuộc gọi đến các phương pháp tĩnh, nhưng bạn có thể mở rộng nó:

namespace Scratch 
{ 
    internal class Foo 
    { 
     // A class to create 
    } 

    class Program 
    { 
     public static T GetInstance<T>() where T : class, new() 
     { 
      return new T(); // Or whatever... 
     } 

     public static T CallGeneric<T>(Func<object> f) 
     { 
      var method = f.Method; 

      var converted = method.GetGenericMethodDefinition().MakeGenericMethod(typeof(T)); 

      return (T) converted.Invoke(null, new object[] {}); 
     } 

     public static T GetEvenMoreGenericInstance<T>() 
     { 
      if(!typeof(T).IsValueType) 
      { 
       return CallGeneric<T>(GetInstance<object>); 
      } 
      return default(T); 
     } 

     static void Main(string[] args) 
     { 
      var a = GetEvenMoreGenericInstance<int>(); 
      var b = GetEvenMoreGenericInstance<Foo>(); 
     } 
    } 
} 
+0

Tôi thích việc sử dụng sự phản chiếu :) – Laurence

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