2009-12-17 9 views
16

Tôi có một số lớp học mà không triển khai một giao diện nhất định nhưng cấu trúc tuân thủ giao diện đó.Tự động tạo trình bao bọc để triển khai giao diện

interface IFoo { 
    void method(); 
} 

class Bar { // does not implement IFoo 
    public void method() {...} 
} 

Bây giờ, tôi có thể viết một wrapper xung quanh những lớp học mà chỉ đơn giản uỷ thác cho lớp bọc

class BarWrapper : IFoo { 
    Bar bar = new Bar(); 
    public void method() 
    { 
     bar.method(); 
    } 
} 

Nhưng đó là rất nhiều công việc tẻ nhạt. Những lớp bao bọc đó có thể được tạo tự động không? Một cái gì đó như:

IFoo foo = CreateWrapper<IFoo>(new Bar());

tôi chắc chắn rằng bạn có thể làm điều này với Reflection.Emit nhưng tôi chưa từng sử dụng đó và nó không giống rất dễ dàng ở cái nhìn đầu tiên.

Có cách nào dễ dàng hơn hoặc có thể là thư viện đã triển khai tính năng này?

+0

Nếu bạn kết thúc phải viết chính bạn, điều này có thể giúp ích như một ví dụ liên quan: http://stackoverflow.com/questions/847809/how-can-i-write-a-generic-container-class-that-implements-a-given-interface-in -c/847975 # 847975 –

Trả lời

2

Bạn có thể muốn xem Dự án của Castle Project DynamicProxy. Đó là những gì Rhino.Mocks sử dụng cho proxy loại của nó.

Tôi chưa tự mình sử dụng, vì vậy tôi không biết bạn cần bao nhiêu công sức, nhưng tôi cho rằng đó là điểm khởi đầu tốt.

+0

AFAIK, phiên bản hiện tại của Proxy động chỉ hoạt động trên các giao diện và các loại cụ thể, và chỉ có thể chặn các phương thức ảo. Nó không lập bản đồ. Tuy nhiên, nó có thể giải quyết vấn đề này trong tương lai: http://using.castleproject.org/display/CASTLE/Dynamic+Proxy+3+design+meeting (cuộn xuống "Loại Gói") –

+0

@Mark: Câu hỏi chỉ đề cập đến làm việc với các giao diện, do đó, âm thanh không giống như một hạn chế đáng kể có liên quan đối với tôi. –

+0

@Jon Skeet: Vâng, nhưng anh ấy muốn bọc/proxy một lớp cụ thể mà không thực hiện một giao diện cũng như không có các phương thức ảo, vì vậy tôi nghĩ nó rất phù hợp. –

0

Nếu bạn sẵn sàng để sử dụng NET 4, một giải pháp có thể để xác định lớp wrapper như một DynamicObject, và chuyển đổi các cuộc gọi đến các phương pháp năng động cho các cuộc gọi đến lớp bọc bằng cách sử dụng phản xạ (Tôi không chắc chắn nếu điều đó thực sự sẽ ít hoạt động hơn, dù sao đi nữa, cũng tính đến các mối quan tâm hiệu suất có thể có liên quan đến việc sử dụng sự phản chiếu).

0

Mặc dù tôi chưa tự sử dụng chúng tôi nghĩ rằng các mẫu T4 trong Visual Studio có thể được sử dụng để tạo mã các loại động link text.

0

Dưới đây là một cách tiếp cận hơi khác nhau bằng cách sử dụng Generics. Điều này sẽ cần một chút suy nghĩ công việc hơn. Bạn cần triển khai trình bao bọc cho mỗi Giao diện và gọi tất cả các phương thức có phản ánh.

class FooWrapper<T> : IFoo 
{ 
    private T obj; 

    public FooWrapper(T obj) 
    { 
     this.obj = obj; 
    } 

    public void method() 
    { 
     // call method with reflection 
     // obj.method(); 
    } 
} 

IFoo foo = new FooWrapper(new Bar()); 
+0

+1: sẽ thực hiện tương tự. Thêm một số bộ đệm phản chiếu để giảm thiểu hiệu suất của hình phạt thêm bằng cách tìm kiếm các phương thức bằng cách phản chiếu –

+1

Ý tưởng hay, nhưng nếu bạn đang sử dụng Reflection, thì bạn cũng có thể sử dụng một số giải pháp gõ vịt hiện có. Cuối cùng, vì lý do hiệu suất, bạn sẽ kết thúc Emiting mã IL và tái phát minh bánh xe. – Groo

8

Những gì bạn đang cố gắng hoàn thành, được gọi là nhập vịt. Có một số thư viện chuyên dụng sẽ cho phép bạn làm điều đó, mặc dù tôi chưa sử dụng bất kỳ thư viện nào trong số đó.

Với ít nỗ lực (và một số phản ánh), bạn có thể sử dụng Castle Dynamic Proxy để thực hiện điều đó, sử dụng phương pháp được nêu here.

Nếu vì một lý do nào đó, phương pháp tiếp cận dựa trên kẻ chặn sẽ không được chấp nhận đối với bạn Proxy động không hỗ trợ tính năng này, nhưng nếu bạn sử dụng phiên bản 2.2 beta, sẽ khá dễ dàng cách gõ mạnh mẽ (không sử dụng các trình chặn), bằng cách cung cấp trình tạo loại proxy của riêng bạn (hãy xem cách mixin được triển khai).

+1

+1 Cảm ơn bạn đã tham gia :) –

3

Bạn có thể tạo một lớp mới

class SubBar : IFoo, Bar { 
} 

và nhanh chóng đó (Giả sử Bar thực sự có ducktype, ví dụ:, chính xác IFoo phương pháp).

5

Nếu bạn muốn hỗ trợ nhập Duck nhẹ nhàng và đơn giản, bạn cũng có thể xem: Duck Typing project. Nó hoạt động với .Net 2.0 và mới hơn.

dụ sử dụng (lấy từ David Meyer's site):

public interface ICanAdd 
{ 
    int Add(int x, int y); 
} 

// Note that MyAdder does NOT implement ICanAdd, 
// but it does define an Add method like the one in ICanAdd: 
public class MyAdder 
{ 
    public int Add(int x, int y) 
    { 
     return x + y; 
    } 
} 

public class Program 
{ 
    void Main() 
    { 
     MyAdder myAdder = new MyAdder(); 

     // Even though ICanAdd is not implemented by MyAdder, 
     // we can duck cast it because it implements all the members: 
     ICanAdd adder = DuckTyping.Cast<ICanAdd>(myAdder); 

     // Now we can call adder as you would any ICanAdd object. 
     // Transparently, this call is being forwarded to myAdder. 
     int sum = adder.Add(2, 2); 
    } 
} 

Sử dụng phương pháp mở rộng, bạn có thể đơn giản hóa nó thành một cái gì đó như thế này (simlar để Bart De Smet's cú pháp)

MyAdder myAdder = new MyAdder(); // this doesn't implement the interface 
ICanAdd adder = myAdder.AsIf<ICanAdd>(); // but it quacks like a duck 
int sum = adder.Add(2, 2);