2009-08-06 42 views
10

我正在使用一個我無法編輯的類,它有一個屬性(布爾型),它會很好地通知它何時發生變化,我無法編輯屬性獲取或設置,因爲我正在導入該類從一個.dll(我沒有代碼)。在屬性上觸發事件/功能? (C#)

如何創建在屬性更改時觸發的事件/函數?

其他
它只是在它自己的類中直接更改爲基礎私有變量。

E.g.

private bool m_MyValue = false; 

public bool MyValue 
    { 
    get { return m_MyValue; } 
    } 

private void SomeFunction() 
    { 
    m_MyValue = true; 
    } 

回答

10

你不能,基本上......不是沒有使用類似於調試器API的東西來在執行時注入代碼並修改原始庫的IL(我不推薦這些解決方案之一;除了任何東西否則可能違反圖書館的許可)。

基本上,如果一個屬性不支持通知,它不支持通知。你應該尋找一種不同的方式來解決你的問題。 (例如,投票是否工作?)

+0

我想我將不得不走下來的投票路線,不是我所期待的,因爲數據可以在調查時機來reduntant(我想要在數據被其他功能使用之前捕獲數據) – ThePower 2009-08-06 10:52:19

+0

或者用你自己的支持INotify或你自己的實現的類來包裝類? – Pondidum 2009-08-07 10:11:01

+0

@安迪:這取決於。如果你這樣做,那麼你不能使用類作爲原始類型,代碼中的其他位可能需要。 – 2009-08-07 10:37:46

5

你不能直接這樣做[爲喬恩斯基特說],除非它是虛擬的,你在一個位置攔截類的所有實例的創作,並有到影響實際支持字段沒有變化propget的'價值'。

蠻力的唯一方法是使用Mono.Cecil或MS CCI來測試道具設定器la this DimeCast on Cecil。 (或PostSharp)

但是,這不會捕獲對後臺字段的內部更改(如果甚至有一個)。 (這是爲什麼包裝可能不會工作)。

更新:鑑於你的更新,你肯定試圖陷入潛在的領域變化,唯一的方法是使用PS/CCI /塞西爾和分析流來攔截所有現場更新。總之,不是很可行。

1

您將需要創建一個類,該類包裝在dll中的類,在setter屬性內使用常規方法在該處引發事件。

+2

但是,這不會通過其setter捕獲組件所引起的內部更新,也不會直接更改poptabop反映的內部狀態。 – 2009-08-06 10:49:08

-1

您可以嘗試繼承它並使用它的孩子而不是它。 重寫屬性的「set」,以便引發事件。

編輯:......只有當財產是在父類中的虛...

+0

唯一可行的是該屬性被標記爲虛擬... – 2009-08-06 12:13:13

+0

是...我同意...對於錯誤的人抱歉... – 2009-08-07 07:58:07

1

你能不能從類繼承和隱藏屬性?事情是這樣的......

class MyClass : BaseClass 
{ 
    // hide base property. 
    public new bool MyProperty 
    { 
     get 
     { 
      return base.MyProperty; 
     } 

     set 
     { 
      base.MyProperty = value; 
      RaiseMyPropertyChangedEvent(); 
     } 
    } 
} 
+0

同http://stackoverflow.com/questions/1238137/creating-an-事件上一個屬性-C/1238154#1238154。 (並更新到Q意味着這將無法正常工作) – 2009-08-06 10:52:59

+0

唯一可行的是該屬性被標記爲虛擬... – 2009-08-06 12:13:50

+1

@Thomas:不,'新'修飾符關鍵字不需要基地是虛擬的。 – 2009-08-06 12:19:02

3

可以說,這樣做的唯一途徑是創造某種「守望者」組成的,在一個單獨的線程中運行,其工作是在間隔讀取屬性和提高物業價值發生變化時的事件。當然,這個解決方案會在線程和同步的黑暗水域中航行。

假設您的應用程序對於此對象是單線程的,您最簡潔的解決方案是通過代理對象對此對象進行方法調用。它會檢查財產的前後狀態,並在事件發生變化的情況下提出事件。

這裏是我說的什麼一個簡單的例子:

public class SomeProxy 
{ 
    public SomeProxy(ExternalObject obj) 
    { 
     _obj = obj; 
    } 

    public event EventArgs PropertyChanged; 

    private bool _lastValue; 

    private ExternalObject _obj; 

    protected virtual void OnPropertyChanged() 
    { 
     if(PropertyChanged != null) 
      PropertyChanged(); 
    } 

    protected virtual void PreMethodCall() 
    { 
     _lastValue = _obj.SomeProperty; 
    } 

    protected virtual void PostMethodCall() 
    { 
     if(_lastValue != _obj.SomeProperty) 
      OnPropertyChanged(); 
    } 

    // Proxy method. 
    public SomeMethod(int arg) 
    { 
     PreMethodCall(); 
     _obj.SomeMethod(arg); // Call actual method. 
     PostMethodCall(); 
    } 
} 

很明顯,你可以建立這種代理模式到合適的對象 - 你只需要知道所有呼叫不得不經歷當你期望它成爲事件的代理人時。

+1

+1對於完整的例子(OP讓他很清楚他想把它當作一個黑盒子,所以答案不適合IMNSHO) – 2009-08-06 14:11:15

2

如前所述,最直接的方法(以及需要對代碼進行最少更改的方法)是使用諸如PostSharp之類的AOP庫。

然而,使用傳統的C#/ .NET通過使用dependency property pattern可以實現一個解決方案,通過WPF使用,效果很好。我建議閱讀本文,並考慮爲您的項目實施此類系統(或至少其簡化版本),如果適用的話。

0

我認爲亞歷克斯的包裝理念是好的,但是,鑑於最重要的是你知道在使用之前價值被改變了,你可以簡單地將通知移動到吸氣劑,規避內部價值變化的擔憂。這樣,你得到類似的東西投票而可靠:

class MyClass : BaseClass 
{ 
    //local value 
    private bool local; 

    //first access yet? 
    private bool accessed = false; 

    // Override base property. 
    public new bool MyProperty 
    { 
     get 
     { 
      if(!accessed) 
      { 
       // modify first-get case according to your taste, e.g. 
       local = base.MyProperty; 
       accessed = true; 
       RaiseMyPropertyChangedBeforeUseEvent(); 
      } 
      else 
      { 
       if(local != base.MyProperty) 
       { 
        local = base.MyProperty; 
        RaiseMyPropertyChangedBeforeUseEvent(); 
       } 
      } 

      return local; 
     } 

     set 
     { 
      base.MyProperty = value; 
     } 
    } 
}