2009-09-14 33 views
5

Tôi đang triển khai giao diện chung (iqueryprovider, cụ thể). tại một số điểm, tôi buộc phải trả về một kết quả chung chung, mà tôi cần phải nhận được từ một số giao diện nội bộ:các hạn chế và giao diện biến kiểu chung

public TResult Execute<TResult>(...) { 
    return something.Foo<TResult>(); 
} 

nơi something.Foo là

public T Foo<T>() where T: MyBaseClass, new() { 
    ... 
} 

này dĩ nhiên thổi lên vì bên ngoài được xác định TResult không có các hạn chế cùng loại như câu hỏi nội bộ được xác định T.: có cách nào để làm cho TResult ngon miệng với Foo không? tôi có thể bằng cách nào đó một cách rõ ràng kiểm tra cho hai điều kiện và ép buộc biến loại?

Trả lời

2

Bạn có thể thử một cái gì đó như thế này:

public TResult Execute<TResult>(...) 
{ 
    if (typeof(TResult) is MyBaseClass) 
    { 
     Type mytype = typeof(TResult); 
     MethodInfo method = typeof({TypewhereFoo<>IsDeclared}).GetMethod("Foo"); 
     MethodInfo generic = method.MakeGenericMethod(myType); 
     return (TResult)generic.Invoke(this, null); 
    } 
    else 
    { 
    // Throw here 
    } 
} 
+2

* thở dài * trong khi điều đó hoạt động, điều đó thật khó chịu, đặc biệt là trong mã cấp khung. – kolosy

+0

tôi đã kết thúc bằng cách này. Tôi không phải là một fan hâm mộ của sự phụ thuộc mềm vào phương pháp này, nhưng nó đánh bại các hạn chế, và vẫn thực hiện các cuộc gọi phản chiếu trên một số thứ khác mà phương thức nội bộ đã làm. – kolosy

0

Bạn sẽ có thêm những hạn chế loại phương pháp chung của bạn:

public TResult Execute<TResult>(...) where TResult: MyBaseClass, new() { 
    return something.Foo<TResult>(); 
} 
+1

không hoạt động, vì chữ ký phương thức đó được xác định trên giao diện tôi không kiểm soát. thêm những hạn chế đó làm cho phương thức đó trở thành quá tải đối với việc triển khai giao diện. – kolosy

1

Nope. Nếu TResult không có ràng buộc về nó, thì nó có thể là bất kỳ thứ gì cũ. Nếu phương thức trợ giúp của bạn không thể thực hiện bất kỳ điều gì cũ, thì bạn sẽ cần phải có một phương thức trợ giúp tốt hơn. Giao diện yêu cầu bạn cung cấp nhiều dịch vụ hơn người trợ giúp của bạn có thể cung cấp, do đó, bạn sẽ phải thực hiện công việc để cung cấp dịch vụ đó.

0

Ouch ... bạn gặp rắc rối. Không có cách nào để gọi một thứ gì đó.Foo() vì bạn không có loại tương thích. Bạn có thể 'Hack' này bằng cách tạo ra một 'wrapper' loại đó là tương thích để gọi Foo() và sau đó 'Unwrap':

class MyNastyFix<T> : MyBaseClass 
    { 
     public T Unwrap() 
     { 
      //assert that T has the correct base type 
      if (!typeof(T).IsSubclassOf(typeof(MyBaseClass))) 
       throw new ArgumentException(); 
      //must use reflection to construct 
      T obj = (T)typeof(T).InvokeMember(null, BindingFlags.CreateInstance, null, null, null); 
      //cast to a type of MyBaseClass so we can copy our values 
      MyBaseClass c = (MyBaseClass)(object)obj; 
      c.SomeValue = this.SomeValue; 
      return obj; 
     } 
    } 

    public static TResult Execute<TResult>() 
    { 
     return something.Foo<MyNastyFix<TResult>>().Unwrap(); 
    } 

Cập nhật: Câu trả lời phản ánh có thể là một cách tiếp cận tốt hơn nếu mà làm việc.

+0

yup, đó là biến thể của câu trả lời phản chiếu khác ... – kolosy

0

Thay đổi Foo để kiểm tra các ràng buộc tại thời gian chạy:

public T Foo<T>() { 
    if (!typeof(T).IsAssignableFrom(typeof(MyBaseClass)) 
     || !typeof(T).GetConstructor(...)) 
     throw new System.NotImplementedException(); 
    ... 
} 

Các khó khăn chung được kiểm tra tại thời gian biên dịch nên họ không thể căn cứ vào điều kiện thời gian chạy.

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