2014-10-01 41 views
-1

比方說,我想創建一個DLL庫,以簡單易用的方式提供通用文件系統服務。這個庫可以用於第三方.NET應用程序。 比方說,這個庫只提供了這個接口給公衆:如何在C#中開發一個庫時做適當的異常處理?

public interface IFileSystemService 
{ 
    void CreateDirectory(string path); 
    void DeleteDirectory(string path); 
    bool DirectoryExists(string path); 
    IEnumerable<string> EnumerateDirectories(string path); 
    void DeleteFile(string path); 
    bool FileExists(string path); 
    void CopyFile(string sourcePath, string destinationPath, bool overwriteExisting); 
    // ... and other methods 
} 

什麼是異常處理的最佳實踐,當談到從System.IO命名空間(如FileInfo實現使用標準的.NET類這個接口, DirectoryInfoDirectoryFile等...)? 如何讓這個庫強大且易於客戶端代碼使用?我該如何做到這一點,以便錯誤處理的客戶端代碼乾淨且不會過於複雜?

+0

https://github.com/aspnet/FileSystem – SLaks 2014-10-01 14:06:44

+0

什麼是清晰而不復雜的錯誤處理? – Reniuz 2014-10-01 14:09:38

+0

@reniuz:我預計這個評論......不確定,我不能給出確切的定義,我希望在社區上有一些共識。例如。對我來說,有一件事情是用少量的try/catch塊編寫客戶端代碼...也許嘗試使用不超過一個或兩個catch塊的塊...太多try/catchs混淆代碼。例如。當我做CopyFile()我想只有一種類型的異常拋出更多的細節在InnerException也許。不知道這是否是正確的方法,但這對我目前意味着什麼。 – matori82 2014-10-01 14:19:52

回答

2

最好的做法是盡你所能從異常中恢復,但如果你不能做任何事情,讓異常傳播給調用者並讓他們處理它。

如何使庫強大且易於使用,儘可能多地爲您的圖書館提供文檔。您可以使用XML的文檔,包括獲得的元數據正確拋出什麼異常爲DLL

(從Directory.CreateDirectory(string)採取評論)

public interface IFileSystemService 
{ 

    /// <summary> 
    /// Creates all directories and subdirectories as specified by <paramref name="path"/>. /// 
    /// </summary> 
    /// 
    /// <returns> 
    /// A <see cref="T:System.IO.DirectoryInfo"/> as specified by <paramref name="path"/>. /// 
    /// </returns> 
    /// <param name="path">The directory path to create.</param> 
    /// <exception cref="T:System.IO.IOException">The directory specified by <paramref name="path"/> is read-only.</exception> 
    /// <exception cref="T:System.UnauthorizedAccessException">The caller does not have the required permission.</exception> 
    /// <exception cref="T:System.ArgumentException"><paramref name="path"/> is a zero-length string, contains only white space, or contains one or more invalid characters as defined by <see cref="F:System.IO.Path.InvalidPathChars"/>. 
    /// 
    /// -or- 
    /// <paramref name="path"/> is prefixed with, or contains only a colon character (:).</exception> 
    ///<exception cref="T:System.ArgumentNullException"><paramref name="path"/> is null.</exception> 
    ///<exception cref="T:System.IO.PathTooLongException">The specified path, file name, or both exceed the system-defined maximum length. For example, on Windows-based platforms, paths must be less than 248 characters and file names must be less than 260 characters.</exception> 
    ///<exception cref="T:System.IO.DirectoryNotFoundException">The specified path is invalid (for example, it is on an unmapped drive).</exception> 
    ///<exception cref="T:System.NotSupportedException"><paramref name="path"/> contains a colon character (:) that is not part of a drive label ("C:\").</exception> 
    void CreateDirectory(string path); 

    //Do similar comments for the rest. 
    void DeleteDirectory(string path); 
    bool DirectoryExists(string path); 
    IEnumerable<string> EnumerateDirectories(string path); 
    void DeleteFile(string path); 
    bool FileExists(string path); 
    void CopyFile(string sourcePath, string destinationPath, bool overwriteExisting); 
    // ... and other methods 
} 
1

什麼是異常處理的最佳實踐時,它通過使用來自System.IO名稱空間的標準.NET類(例如,FileInfo,DirectoryInfo,Directory,File等)來實現此接口?

就我而言,最佳實踐是讓異常冒泡。作爲一個「框架」實現者,你不知道你的API用戶的異常處理意圖是什麼。而且因爲你不知道這個用戶的意圖,所以最好拋出異常。

  1. 通過讓異常沸騰起來,你讓一個到達的地方除外實際發生
  2. 完整的堆棧跟蹤也讓一個處理一個要趕上基於一個背景
例外

基於一個Eric Lippert的博客文章,Vexing Exceptions我再也找不到,我記得他說這是最好看的代碼,如:

if (condition) throw new Exception("message"); 

比看到:

try { something(); } 
catch (Exception ex) { throw new Exception(); } 

因爲堆棧跟蹤是每一個異常被重新拋出時間被重置了。否則,你可以這樣做:

try { something(); } 
catch (Exception ex) { 
    handleTheExceptionInternallyForYourPurpose(); 
    throw ex; // simply let the exception flow go its way to the top, to the caller. 
} 

另外,這一切都取決於你的行爲預期。假設您不希望允許空值作爲path參數,那麼您可能希望在出現這種情況時拋出ArgumentNullException

public void CreateDirectory(string path) { 
    if (path == null) throw new ArgumentNullException("path"); 
    if (string.IsNullOrWhiteSpace(path)) throw new ArgumentException("path"); 

    // create your directory here based on the path provided... 
} 

我怎樣才能讓這個庫強大和易於通過客戶端代碼中使用?

我敢打賭,你不能爲其他程序員編程。你可能擁有世界上最好的圖書館,一個經驗較少或者不尊重SRP的圖書館最終可能會出現雜亂的代碼。它屬於每個程序員,遵循一些準則並尊重最佳實踐和原則。可悲的是,這些原則很少被遵循,至少在我的角落。無論你做什麼,根據你的情況,幾乎總會有更好的方式來做事情。

我怎樣才能讓這個所以對於錯誤處理客戶端代碼是乾淨的,沒有過於複雜?

複雜的東西將永遠是複雜的代碼,所以沒有辦法逃脫。通過堅持SOLID原則,並使用明天的最佳實踐,您將擁有一個簡單易懂的圖書館。

XML Comments也是一個很好的方式去圖書館,以便智能感知可以在輸入時顯示它。