2011-12-05 46 views
47

Tôi muốn tạo đối tượng proxy động để thêm chức năng nhất định vào đối tượng.Cách tạo proxy động đơn giản trong C#

về cơ bản tôi muốn nhận một đối tượng, bọc nó với một đối tượng trông giống hệt với bản gốc tôi đã nhận và chặn tất cả các cuộc gọi.

class Wrapper : DynamicProxy// dynamic proxy is not a reall class, but i guess something like this exists... 
{ 
    public static T Wrap(T obj) 
    { 
     return (T) new Wrapper(obj); 
    } 

    public override object InterceptCall(MethodInfo info, object[] args) 
    { 
     // do stuff 
    } 

} 

Chỉ cần làm rõ, tôi muốn làm một cái gì đó tương tự như các nhà máy kênh WCF ...


tôi thêm một tiền thưởng, bởi vì tôi cần một cách tốt để proxy các lớp (không phải là giao diện) và để xử lý các phương thức không ảo (như thể tôi đã kế thừa và thêm một methond theo từ khóa "mới"). Tôi chắc chắn tất cả điều này là rất có thể như. Net hiện nó.

+4

có bạn nhìn vào http://www.castleproject.org/dynamicproxy/index.html? –

+0

@ np-hard nếu bạn đăng câu trả lời này, tôi sẽ chấp nhận nó ... không phải 100% những gì tôi đang tìm kiếm, nhưng đủ tốt. –

+0

Bạn có biết loại bạn muốn proxy vào thời gian biên dịch hay chỉ khi chạy? – Sneal

Trả lời

12

Tôi nên viết điều này sớm hơn, nhưng đừng bận tâm.

Sự cố của tôi có một "dấu hiệu" đặc biệt mà tôi cần để có thể thực hiện các lớp proxy chứ không phải giao diện.

Có hai giải pháp này:

  1. Real Proxy và bạn bè, về cơ bản có nghĩa là sử dụng Net Remoting. Yêu cầu một kế thừa từ ContextBoundObject.

  2. Tạo proxy bằng cách sử dụng System.Reflection.Emit được thực hiện bởi spring bạn cũng có thể xem mã số ProxyFactoryObject của chúng. Dưới đây là another ba articles trên subject.

Bằng cách này, cách tiếp cận thứ hai có giới hạn đáng kể, bạn không thể ủy quyền các phương pháp không ảo.

+0

Bạn có thể thêm một ví dụ về cách thực hiện điều này không? Một cái gì đó rất cơ bản ... – Tsury

+0

Không. Nhưng bạn có thể làm theo các liên kết và tìm thấy các ví dụ tốt hơn và khám phá hơn bất cứ điều gì tôi có thể viết ở đây. –

+0

Liên kết 'http: // dcooney.com /' của bạn bị hỏng. Bạn có lựa chọn khác không? – Basic

5

Hãy xem PostSharp. Tôi không biết cách nào để làm những gì bạn muốn trong vani .Net, nhưng PostSharp cung cấp những thứ như "OnMethodBoundaryAspect" có thể được sử dụng để thay thế hoặc bọc mã bên trong phương thức.

Tôi đã sử dụng nó để làm những việc như khai thác gỗ, xác nhận tham số, xử lý, vv

Có một Community Edition miễn phí, mà nên làm việc cho bạn là ngoại lệ. Bạn sẽ cần nó được cài đặt trên máy phát triển của bạn, cũng như bất kỳ máy chủ xây dựng nào mà bạn sử dụng.

+0

Postsharp hoạt động tại thời gian biên dịch cho các loại đã biết. Tôi không nghĩ là những gì OP cần thiết – sam

33

Bạn có thể thực hiện việc này với sự kết hợp của DynamicObjectImpromptuInterface nhưng bạn sẽ phải có Giao diện triển khai các chức năng và thuộc tính bạn muốn proxy.

public interface IDoStuff 
{ 
    void Foo(); 
} 

public class Wrapper<T> : DynamicObject 
{ 
    private readonly T _wrappedObject; 

    public static T1 Wrap<T1>(T obj) where T1 : class 
    { 
     if (!typeof(T1).IsInterface) 
      throw new ArgumentException("T1 must be an Interface"); 

     return new Wrapper<T>(obj).ActLike<T1>(); 
    } 

    //you can make the contructor private so you are forced to use the Wrap method. 
    private Wrapper(T obj) 
    { 
     _wrappedObject = obj; 
    } 

    public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) 
    { 
     try 
     { 
      //do stuff here 

      //call _wrappedObject object 
      result = _wrappedObject.GetType().GetMethod(binder.Name).Invoke(_wrappedObject, args); 
      return true; 
     } 
     catch 
     { 
      result = null; 
      return false; 
     } 
    } 
} 

Bạn có thể tắt khóa học để chọn loại an toàn và đi với một DynamicObject như tôi đã cho thấy rồi thả vịt.

Tôi đã tạo phiên bản có thể mở rộng trong suốt của proxy đối tượng này và mở nó here.

+0

Bạn có thể nói một từ về cách thức hoạt động của ImpromptuInterface dưới mui xe? Đó là, kỹ thuật nào 'ActLike' sử dụng để tạo ra một đối tượng thuộc loại nào? Một số loại tạo mã byte? – Lii

+0

@Lii Tôi không phát triển ImpromptuInterface. Nhưng nó sử dụng DLR để liên kết động với các hàm trên đối tượng ducktyped. Và sau đó nó sử dụng cùng một thủ thuật đó để đưa nó vào Giao diện mà bạn chỉ định. – albertjan

+0

Tác động hiệu suất của một cái gì đó như thế này là gì? AFAIK '.GetType()' không thực sự thân thiện với hiệu năng. – FrankerZ

2

Tùy chọn khác là ContextBoundObject.

Đã có một bài viết về CodeProject khoảng 8-9 năm trở lại bằng cách sử dụng phương pháp này để theo dõi các cuộc gọi phương thức.

0

Để thêm bất kỳ chức năng nào trước và sau mỗi chức năng trong một lớp, proxy thực là một cách tiếp cận tốt.

Vì vậy, bây giờ trong T có thể là bất kỳ TestClass nào. Tạo Instance như thế này cho TestClass-

var _instance = (object) DynamicProxy (TestClass) .GetTransparentProxy();

Mã cho động Proxy-

class DynamicProxy<T> : RealProxy 
    { 
     readonly T decorated; 

     public DynamicProxy(T decorated) : base(typeof(T)) 
     { 
      this.decorated = decorated; 
     } 

     public override IMessage Invoke(IMessage msg) 
     { 
      var methodCall = msg as IMethodCallMessage; 
      var methodInfo = methodCall.MethodBase as MethodInfo; 
      string fullMethodName = $"{methodInfo.DeclaringType.Name}.{methodCall.MethodName}"; 

      try 
      { 
       var result = methodInfo.Invoke(decorated, methodCall.InArgs); 

       return new ReturnMessage(result, null, 0, methodCall.LogicalCallContext, methodCall); 
      } 

      catch (Exception e) 
      { 
       return new ReturnMessage(e, methodCall); 
      } 
      finally 
      { 
      } 
     } 
    } 
Các vấn đề liên quan