2017-02-27 37 views
2

介紹C#如何在抽象類鎖與第三方

我有一個公共抽象類,用抽象的方法,我想從一個工人線程中調用。

當調用該方法時,應鎖定相應的實例以防止計算過程中的狀態更改。

我只想使用抽象類,因爲繼承者的實現是由第三方完成的。

public abstract class MyClass 
{ 
    public abstract MyResult GetData(); 
} 

問題

我的庫由第三方,我認爲他們一無所知的內部實現圖書館。

我不想強迫他們研究我的課程的文檔,然後才能夠實現他們自己的繼承者,因爲我認爲這種不良形式。

我的做法

我的第一個想法是受保護的鎖定對象添加到類和調用方法時就可以鎖定。

但是,爲了使它有用,第三方也必須鎖定它,從而瞭解它。

因爲我不想強迫第三方瞭解內部,我不喜歡這個選項。

public abstract class MyClass 
{ 
    protected readonly object myLock = new object(); 

    public MyResult GetData() 
    { 
     MyResult result; 

     lock(myLock) 
     { 
      result = GetDataInternal(); 
     } 

     return result; 
    } 

    protected abstract MyResult GetDataInternal(); 
} 

背景

我工作的一個數據管道,它運行在一個單獨的線程。

此管道請求特定格式的數據並在後臺處理它。

提供數據可能需要一些時間,所提供的數據依賴於對象的屬性。

在這種情況下,它是3D模型的準備流水線。

問題

怎樣才能鎖定不知道其實現整體目標?

如果沒有這種方式,那麼是否存在一個商定的模式或類似的問題?

+3

只是一個評論。強迫從你的類型繼承的人閱讀文檔,並遵循你提出的規則是不錯的形式,它是絕對必需的**。誠然,你應該讓他們很容易陷入「成功之坑」,但是如果你打算讓他們繼承你的類型,你就不可能做出一種萬無一失的類型。對於你所知道的,他們可以實現方法來返回你所期望的負面效果,並使用這些後代類型將一個大扳手扔進任何代碼的作品中。 –

+0

沒有通用鎖定會「鎖定代碼」而不執行代碼,也不關心鎖定。換句話說,如果某些代碼不鎖定地訪問對象,並且使用某些代碼,則無法在不改變它的情況下神奇地讓第一塊代碼關心鎖。您可以關閉對象,以便僅提供線程安全訪問,例如僅提供其內部的快照,但這也需要更改使用類型的任何第三方代碼。 –

+0

你是對的,閱讀文檔是必須的。但是在這裏我不喜歡這個要求,因爲大多數人都不會識別myLock屬性。我不喜歡在閱讀文檔時才正確使用(大多數情況下)的實現。 – Chillersanim

回答

1

我的庫被第三方使用,我必須假設他們對庫的內部實現一無所知。 (..) 當調用方法時,應鎖定相應的實例以防止計算過程中的狀態更改。

我認爲最好的辦法是..讓他們知道,並確保他們知道他們對此負責。沒有(很多)文檔,你可以很容易地使它變得直觀。

考慮更改抽象類的東西,如:

public interface ILockable 
{ 
    void FreezeDataForCalculations(); 
    void ThawAfterCalculations(); 
} 

public abstract class MyBaseClass<T> where T:ILockable 
{ 
    public abstract T GetData(); 
} 

用法:

public class MyThingie : MyBaseClass<TheActualData> 
{ 
} 

public class TheActualData : ILockable 
{ 
    public string Foo {get;set;} 

    public void FreezeDataForCalculations() { ...???...} 
    public void ThawAfterCalculations() { ....???.... } 
} 

現在,您可以有效地保證:

  • 凡要實現它,有提供他自己的類型,實現額外的接口
  • 誰implementa額外的接口會注意到這兩種方法,他們至少認爲「跆拳道」,並要麼immediatelly理解,或將嘗試諮詢文件
  • 你沒有鎖定的數據,創建者類是負責IT
  • 實施者現在可以選擇 whever實際執行凍結/解凍對,或將其保留爲空,只是自己寫代碼,以在此期間
  • 代碼現在還沒有修改數據可以適當地調用'凍結'和'解凍',並且可以假設執行者做了他所期望的

相反,如果您不能假定他所做的是他所期待的,那麼更改您的庫的API並且不允許使用用戶定義的類型,並將API限制爲僅限於您自己的類型你可以確保這會很好玩。

+0

這是美麗而簡單的。如果有人忽視這一點,那顯然是他們自己的錯。看起來對我來說是一個很好的解決方案。謝謝! – Chillersanim

+0

我認爲這是從原始設計退一步。問題是關於如何隱藏鎖定行爲。 OP的代碼就是這樣做的。這恰恰相反 - 揭示了對鎖的需求並使消費者負責。對原創作品可能還有一些改進的方法,但它完成了這個意圖。有人繼承這個類可以填充所需的功能,但甚至不需要知道鎖定正在進行。 –

+0

查看它的另一種方式 - 這需要有人調用與課程中沒有任何明顯關係的方法。任何類,甚至是一個字符串,都可能需要被保護,以免來自各個線程的狀態變化。我不建議創建一個模式,我們明確地標記需要被鎖定的類,暗示其他所有內容都隱式線程安全。 –