2009-11-24 30 views
8

Vì vậy, tôi chắc chắn điều này đã được trả lời ở đâu đó trước đó, nhưng tôi không thể tìm thấy nó ở bất cứ đâu. Hy vọng một số guru generics có thể giúp đỡ.Phương pháp chung với hành động <T> tham số

public interface IAnimal{} 
public class Orangutan:IAnimal{} 

public void ValidateUsing<T>(Action<T> action) where T : IAnimal 
{ 
    Orangutan orangutan = new Orangutan(); 
    action(orangutan); //Compile error 1 

    //This doesn't work either: 
    IAnimal animal = new Orangutan(); 
    action(animal); //Compile error 2 
} 
  1. loại Đối số 'Đười ươi' là không thể chuyển nhượng để tham số kiểu 'T' loại
  2. Đối số 'IAnimal' không thể chuyển nhượng để tham số kiểu 'T'

Edit: Dựa trên Yuriy và các đề xuất khác, tôi có thể thực hiện một số thao tác như:

public void ValidateUsing<T>(Action<T> action) where T : IAnimal 
{ 
    Orangutan orangutan = new Orangutan(); 
    action((T)(IAnimal)orangutan); 

    //This doesn't work either: 
    IAnimal animal = new Orangutan(); 
    action((T)animal); 
} 

Điều tôi muốn làm là gọi phương thức ValidateUsing như thế này:

ValidateUsing(Foo); 

Thật không may, nếu foo trông như thế này:

private void Foo(Orangutan obj) 
{ 
    //Do something 
} 

tôi phải chỉ định rõ kiểu dữ liệu khi tôi gọi ValidateUsing

ValidateUsing<Orangutan>(Foo); 

Trả lời

6

Tại sao các bạn instantiating một Orangutan nếu bạn có nghĩa vụ phải được chấp nhận bất kỳ IAnimal?

public void ValidateUsing<T>(Action<T> action) where T : IAnimal, new() 
{ 
    T animal = new T(); 
    action(animal); //Compile error 2 

Nếu bạn sử dụng lại thông số chung của bạn, bạn sẽ không có bất kỳ vấn đề loại ...

Bây giờ, đối với lý do tại sao mã của bạn không làm việc với, tất cả những gì bạn đang nói là loại T sẽ xuất phát từ IAnimal. Tuy nhiên, nó có thể dễ dàng là Giraffe dưới dạng Orangutan, do đó bạn không thể chỉ định một số Orangutan hoặc IAnimal cho thông số loại T.

+0

Cảm ơn bdukes, tôi chỉ sử dụng Orangutan làm ví dụ. Có lẽ là một xấu. Tôi muốn có thể gọi hành động với bất kỳ IAnimal nào. Trong mã "thực", IAnimal được lưu trữ như một trường riêng trong lớp. Vì vậy, tôi không thực sự instantiating bất cứ điều gì. –

2

Hãy thử điều này.

Orangutan orangutan = new Orangutan(); 
Action<IAnimal> castedAction = action as Action<IAnimal>; 
castedAction(orangutan); 
+0

Cảm ơn Stan! Tôi sẽ upvote câu trả lời của bạn nếu tôi có đủ danh tiếng. –

2

Tận dụng những thay đổi sau đây:

Orangutan orangutan = new Orangutan(); 
action((T)(IAnimal)orangutan); 


IAnimal animal = new Orangutan(); 
action((T)animal); 
+0

Xin chào Yuriy, điều này hoạt động rất tốt. Nó giúp tôi trở thành một phần của con đường (xem phần chỉnh sửa). Cảm ơn! –

0
public interface IAnimal { } 
public class Orangutan : IAnimal { } 

public void ValidateUsing<T>(Action<T> action) where T : IAnimal 
{ 
    Orangutan orangutan = new Orangutan(); 
    action((T)(orangutan as IAnimal)); // needs to be cast as IAnimal 

    //This doesn't work either: 
    IAnimal animal = new Orangutan(); 
    action((T)animal); // needs to be cast as T 
} 

Nó cũng có vẻ như thực tế là giao diện tạo nên sự khác biệt. Nếu bạn đã có một động vật lớp trừu tượng, thay vì một giao diện, bạn có thể làm điều này:

public abstract class Animal { } 
public class Orangutan : Animal { } 

public void ValidateUsing<T>(Action<T> action) where T : Animal 
{ 
    Orangutan orangutan = new Orangutan(); 
    action(orangutan as T); 

    //This doesn't work either: 
    Animal animal = new Orangutan(); 
    action(animal as T); 
} 
+0

Hi leo lên, nhờ câu trả lời chi tiết. Tôi có xu hướng sử dụng giao diện thường xuyên hơn nhiều so với các lớp trừu tượng (thành phần ưu tiên so với thừa kế và tất cả điều đó), nhưng thật thú vị khi biết rằng nó hoạt động với một lớp trừu tượng. –

4

Có điều là, rằng T đại diện cho một số loại mà bằng cách này thực hiện IAnimal.

Vì vậy, khi bạn cố gắng để biên dịch action(new Organatum()) bạn nhận được một lỗi vì bạn đã tuyên bố rằng hành động nên phải mất một tham số có kiểu T do đó nó có thể là các loại, chúng ta hãy nói, Fish - bạn không thể đúc Organatum đến một số Fish, phải không?

Nếu bạn muốn kích hoạt bất kỳ hành động nào có tham số của một loại thực hiện giao diện IAnimal, sau đó chỉ cần quên về generics và sử dụng Action<IAnimal>.

HTH.

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