2015-06-03 64 views
1

比方說,我有一個Manager類在編譯時限制方法訪問的最佳方式是什麼?

public class Manager { 
    public Item Create() { 
     ... 
     return new Item(...); 
    } 
} 

,我有一個項目類:

public class Item { 
    [AllowCallBy(typeof(Manager))] 
    public Item(...) { 
    } 
    ... 
} 

現在,我想用最簡單,最直接的方法,在分析像AllowCallBy屬性編譯時間並顯示錯誤或警告。如果,在這種特殊情況下,比管理類其他類試圖實例Itemnew Item(...)我想顯示類似「不直接實例化項目類,調用Manager.Create(...),而不是」。

我想至少有一個系統:Roslyn,ReSharper,PostSharp或者別的什麼都可以讓我做到這一點,或者與我試圖達到的目標非常接近。有人可以舉一個例子說明如何使用它以及如何使用它?

+6

這聽起來像一個代碼味道,我不知道你將如何實現在編譯的時候是這樣的,但你應該重新考慮你的設計。可以在Item類中創建一個靜態方法或一個構造函數,它需要一個類型爲Manager的參數,以確保每個項目都與經理或某事有關......這些行... – Habib

+0

我相信你可以用Roslyn編寫一個分析器,警告你,是的。如果您將嚴重性更改爲錯誤,我認爲它也會阻止構建應用程序。 –

+1

問題是,沒有任何東西可以阻止另一位開發人員不理解您的前提,因爲他只是刪除此警告。我認爲更好的方法是從Item Item中刪除特定的需求,用一個manager參數創建一個Item的構造函數,或者向你的問題添加更多的細節,以更好地描述你正試圖解決的*問題* – Sayse

回答

1

好吧,讓我感到驚訝。 PostSharp lets you do exactly what you're looking for。簡而言之,你會使用ComponentInternalAttribute來控制類型的可見性:

public class Item { 
    [ComponentInternal(typeof(Manager))] 
    public Item(...) { 
    } 
    ... 
} 

根據他們的文檔上面鏈接,試圖調用Item的的Manager外構造將產生編譯時警告:

方法Item.ctor不能從[某種其它方法]因爲[ComponentInternal]約束的被引用。

您可以通過改變屬性的嚴重性級別使它成爲一個錯誤:

public class Item { 
    [ComponentInternal(typeof(Manager), Severity = SeverityType.Error)] 
    public Item(...) { 
    } 
    ... 
} 
0

考慮到您實際上可以更改該代碼,您有更好的方法可以實現您的目標,而不是您目前的方法,

例如,您可以將Item類的構造函數標記爲private,並將靜態工廠方法添加到Item類中,該類將負責創建類的實例。

另一種方法是將Item類移動到另一個程序集,將其構造函數標記爲內部並實現另一個類(工廠),它將負責創建不同的Item對象。然後你的類可以從其他程序集中看到,但它不能直接實例化,所以強制代碼用戶使用提供的工廠。

+0

所有這一切都假設代碼可以改變。這很可能是一個傳統的設計問題,因爲很好的原因,不能僅僅適應。這就是羅斯林診斷所適用的地方:在團隊找到解決問題的時間之前,防止再次發生同樣的問題。 –

+0

OP沒有明確提到無法更改當前的代碼,所以我想出了這個答案。我應該刪除它嗎? –

+0

這就是爲什麼我特別強調「警告在同一個圖書館工作的人」。這就是爲什麼讓他們內部不起作用。用私有標記構造函數並創建一個靜態方法將不起作用,因爲Manager的一個實例具有某些用於Item初始化的字段。所以Item不能正確地創建它自己。只有經理可以做到這一點。 –

3

這絕對是@Habib提到的code smell(有人可以鏈接到特定的一個?),但沒有一個更完整的例子,很難提供超出已經在評論中提出的替代方案。我鼓勵你擴大你的樣本或重新考慮你的設計。


但是,我可以提供一個選項,我過去使用過,但不是用於此目的。你可能標誌着Item的構造函數Obsolete

public class Item { 
    [Obsolete("Don't instantiate Item class directly, call Manager.Create(...) instead")] 
    public Item(...) { 
    } 
    ... 
} 

然後在您的Manager類,你會特別是忽略這個警告,你調用構造函數:

public class Manager { 
    public Item Create() { 
     ... 
#pragma warning disable 618 
     return new Item(...); 
#pragma warning restore 618 
    } 
} 

這樣,每當有人試圖在代碼的其他地方創建自己的Item,他們會得到一個level 2 CS0618 warning,表明他們不應該使用使用方法(注意我沒有說不能)在屬性中輸入的文本。如果warnings as errors啓用(所有警告或僅這一個),那麼這將是一個編譯錯誤,因爲你本來想。

要知道,沒有什麼可以阻止他人將這些pragma語句來繞過錯誤。然而,這種方法的開發人員不能說他們不知道,他們不應該使用構造函數。

+0

我想過了。我唯一不喜歡的是ObsoleteAttribute的使用方式不應該如此。但總的來說,這可能是最簡單的解決方案。不過,我希望有一個更清潔的系統與上述系統之一。 –

相關問題