2013-11-20 17 views
1

我想做一個通用的包裝類,可以包裝任何其他類,並添加額外的功能。但是同時我希望能夠在任何我通常使用包裝類的地方使用這個包裝器。目前我使用隱式投射,它工作正常。但是,在一個理想的世界,我想包裝類具有相同的曝光方法和字段的封裝類,就像在這片示例代碼:包裝一個類,同時仍然暴露其所有公共方法,屬性和字段

class Foo 
{ 
    public int Bar() { return 5; } 
} 

class Wrapper<T> 
{ 
    private T contents; 

    public void ExtraFunctionality() { } 
    public static implicit operator T(Wrapper<T> w) { return w.contents; } 
} 



Foo f = new Foo(); 
Wrapper<Foo> w = new Wrapper<Foo>(foo); 

int y = w.Bar(); 

我可以使用一些古老的巫術,反射或其他技巧使這成爲可能?

注意:在C++中我只是重載 - >操作符來操作字段內容而不是包裝器。

+0

聽起來像裝飾的代理。使用T4來生成包裝類的一個選項? – lboshuizen

+0

這是一個猜測,但你有沒有嘗試過'公共課包裝:T'?我不知道這是否可能。 – Silvermind

+0

@Silvermind沒有這不可能。 –

回答

1

我不會推薦這個,但既然你提到巫術......你可以使用DynamicObject動態打字。包裝嘗試處理請求的方法。如果不能,它調用轉發給底層包裝的對象:

class DynamicWrapper : DynamicObject 
{ 
    private readonly object _contents; 

    public DynamicWrapper(object obj) 
    { 
     _contents = obj; 
    } 

    public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) 
    { 
     if (binder.Name == "ExtraFunctionality") 
     { 
      // extra functionality 
      return true; 
     } 
     var method = _contents.GetType() 
          .GetRuntimeMethods() 
          .FirstOrDefault(m => m.Name == binder.Name); 

     if (method == null) 
     { 
      result = null; 
      return false; 
     } 

     result = method.Invoke(_contents, args); 
     return true; 
    } 
} 

編輯

沒關係,我只注意到你想,你通常會使用到處使用這個實例包裝類型的一個實例。 您必須將字段/屬性/變量聲明更改爲dynamic才能使用它。

+0

只要我可以爲此寫一個演員重載,它應該是可以的。我明天會試試看! (我也想知道這個開銷是多少,任何想法?) –

+0

順便說一句,你還需要重寫'TryGetMember'和'TrySetMember'來獲取/設置包裝實例的屬性。 – dcastro

+0

「鑄造超負荷」是什麼意思?開銷不是那麼高,我記得Eric Lippert在這篇文章上看過一篇文章,我認爲一段動態代碼會在運行時編譯,然後儘可能緩存。 – dcastro

0

您可以使用System.Reflection.Emit命名空間中的類動態生成類型。這link可以給你一個很好的起點。

+0

但是,這將改變運行時的接口,而做w.Bar()我需要知道接口在編譯時。 –

+0

如果生成的類型來自包裝類型或實現相同的接口,則接口不一定會更改。但是,您可能需要在客戶端類中注入包裝類,以允許注入包裝類而不是原來的包裝類。一些IoC框架實現了攔截功能,允許在使用該方法的特定方法之前或之後運行代碼。 – Markus

相關問題