我有一段用流利的語法編寫的軟件。方法鏈有一個明確的「結束」,在此之前,代碼中實際上沒有任何有用的東西(比如NBuilder,或者Linq-to-SQL的查詢生成在我們使用ToList()遍歷我們的對象之前並不實際觸及數據庫) )。如何在C#中強制使用方法的返回值?
我遇到的問題是其他開發人員對正確使用代碼存在困惑。他們忽略稱之爲「結局」的方法(因此從來沒有真正「做任何事情」)!
我對執行我的一些方法的返回值的使用感興趣,以便我們永遠不要「調用」Finalize()「或」Save()「方法來」結束鏈「工作。
考慮下面的代碼:
//The "factory" class the user will be dealing with
public class FluentClass
{
//The entry point for this software
public IntermediateClass<T> Init<T>()
{
return new IntermediateClass<T>();
}
}
//The class that actually does the work
public class IntermediateClass<T>
{
private List<T> _values;
//The user cannot call this constructor
internal IntermediateClass<T>()
{
_values = new List<T>();
}
//Once generated, they can call "setup" methods such as this
public IntermediateClass<T> With(T value)
{
var instance = new IntermediateClass<T>() { _values = _values };
instance._values.Add(value);
return instance;
}
//Picture "lazy loading" - you have to call this method to
//actually do anything worthwhile
public void Save()
{
var itemCount = _values.Count();
. . . //save to database, write a log, do some real work
}
}
正如你所看到的,這個代碼的正確用法是這樣的:
new FluentClass().Init<int>().With(-1).With(300).With(42).Save();
的問題是,人們正在使用這種方式(思維它達到了與上面相同):
new FluentClass().Init<int>().With(-1).With(300).With(42);
這麼普遍的是這個問題,完全好的意圖,另一位開發人員實際上曾改變過「Init」方法的名稱,以表明該方法正在做軟件的「真正的工作」。
像這樣的邏輯錯誤是非常難以發現的,當然,它編譯,因爲它是完全可以接受的調用返回值的方法,只是「假裝」它返回無效。 Visual Studio不關心你是否這樣做;你的軟件仍然會編譯和運行(儘管在某些情況下我相信它會引發警告)。當然,這是一個很棒的功能。設想一個簡單的「InsertToDatabase」方法,它將新行的ID作爲整數返回 - 很容易看出有些情況下我們需要該ID,還有一些情況下我們可以不用它。
就這款軟件而言,絕對沒有任何理由避開方法鏈末尾的「保存」功能。這是一個非常專業化的工具,唯一的收穫來自最後一步。
如果他們調用「With()」而不是「Save()」,我希望某人的軟件在編譯器級別上失敗。
這似乎是一個傳統手段不可能的任務 - 但這就是爲什麼我來找你們。是否有一個屬性,我可以用來防止一個方法被「鑄造成無效」或一些這樣的?
注:已經被建議我實現這一目標的另一種方法是編寫了一套單元測試來執行這一規則,並使用類似http://www.testdriven.net東西,它們綁定到編譯器。這是一個可以接受的解決方案,但我希望有更優雅的東西。
+1 [return-value] ;-) – 2011-03-23 20:14:11
在黑暗中拍攝的總數,我不知道這是可能的,但也許.NET代碼合同?我認爲它們被內置到.NET 4.0中 – Roly 2011-03-23 20:14:23
Code Contracts沒有屬性或斷言,它需要檢查返回值。 – user7116 2011-03-23 20:46:59