C# .NET 開發心得


1. 工作路徑問題

1. 多項目構成的解決方案,Web APP作為啟動項目時的工作路徑

//當前執行的exe文件名
//C:\\Program Files\\IIS Express\\iisexpress.exe
System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName
//獲取和設置當前目錄(該進程從中啟動的目錄)的完全限定目錄
//C:\\Program Files\\IIS Express
System.Environment.CurrentDirectory
//獲取應用程序當前工作目錄。這個不一定是程序從中啟動的目錄。這是任何應用程序最后一次操作過的目錄,比如你用Word打開了E:\doc\my.doc這個文件,此時執行這個方法就返回E:\doc了
//"C:\\Program Files\\IIS Express
System.IO.Directory.GetCurrentDirectory()
//獲取程序的基目錄,往往是項目實際存儲的目錄
//D:\\Code\\location\\XiaKe\\XiaKeWebAPI\\
System.AppDomain.CurrentDomain.BaseDirectory
//獲取和設置包括該應用程序的目錄的名詞
//D:\\Code\\location\\XiaKe\\XiaKeWebAPI\\
System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase

 2. 程序集影像復制問題

1. bin, obj, properties 目錄

bin 目錄用來存放編譯的結果,對應的文件夾下有 Debug 和 Release 兩個版本,為默認的二進制文件輸出路徑。

obj 目錄用來存放編譯過程中生成的中間臨時文件,其中也對應有調試版本和發布版本,在 .NET 中,編譯是分模塊進行的,編譯整個完成后會合並為一個 .DLL 或 .EXE 保存到 bin 目錄下。因為每次編譯時都默認采用增量編譯,即只重新編譯改變了的模塊,obj 保存每個模塊的編譯結果,用來加快編譯速度。是否采用增量編譯,可以通過:項目屬性->配置屬性->高級->增量編譯來設置。

properties 文件夾定義程序集的屬性,一般只有 AssemblyInfo.cs 類文件,用於保存程序集的信息,如名稱,版本等,這些信息一般與項目屬性面板中的數據對應,不需要手動編寫。

2. shadowCopyBinAssembliies 屬性

在 ASP .NET <system.web><hostingEnvironment shadowCopyBinAssembliies="false" /></system.web> 里設置,默認為 true,表示 Bin 目錄中的應用程序的程序集是否影像復制到該應用程序的 ASP.NET 臨時文件目錄中。在有時候對程序進行修改后,可能會出現運行結果仍然保持未修改前的狀態,是因為直接提取臨時文件目錄下的程序集,這種情況下應該手動設置為 false。

3. Debug 提示 "The application is in a break mode." 問題

1. 彈出錯誤提示,然后直接終止程序,通過設置 Debug | Windows | Exception Settings 就可以配置調試器中斷處的異常類型,可以跟蹤拋出異常的位置和信息。

4. Unhandled Exception: System.BadImageFormatException: Could not load file or assembly 'Common, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies.

無法加載依賴項,比如 DLL,可能是因為 DLL 的位數和當前程序的位數不一樣,需要通過 configuration manger 設置為合適的程序位數 Any CPU | x86 | x64。

5. 正則表達式的貪婪匹配與非貪婪匹配

  <div>.*</div> 為貪婪匹配,會盡可能匹配到最遠處;<div>.*?</div> 為非貪婪匹配,匹配到合適的表達式,就結束當前匹配,盡可能少重復。

6. Git 

1. 在clone一個代碼倉庫時,得到的都是其主分支origin/master(origin表示遠端服務器)到本地master,然后可以check out不同的分支到本地,在不同的分支間進行切換時,本地文件系統會隨着發生變化,時刻展現當前分支的文件內容。

7. List<T>排序

Entities.OrderBy(x => x.Start).ToList()

8. 判斷一個IEnumerable<T>的對象中是否包含元素

Entities.Any() 這個函數在命令空間 System.Linq 下

9. Inconsistent Accessibility: Parameter type is less accessible than method

可能原因是構造函數是public,但是所需要的參數是其他類的private。

10. Unit Test 對異常進行測試的兩種方式

大多數情況下使用ExpectedException屬性就可以滿足需求。但是如果需要檢查Exception被捕獲時,條件或者參數值是否成立。可以使用更加復雜的方式。

//Solution 1
//下面大括號內可以填入異常信息,但是不會自動校驗
[TestMethod]
[ExpectedException(typeof(ArgumentNullException){, "ExceptionMessage})]
public void MethodTest()
{
    var obj = new ClassRequiringNonNullParameter( null );
}

//Solution 2
public void MethodTest()
{
    try
    {
        var obj = new ClassRequiringNonNullParameter( null );
        Assert.Fail("An exception should have been thrown");
    }
    catch (ArgumentNullException ae)
    {
        Assert.AreEqual("Parameter cannot be null or empty.", ae.Message);
    }
    catch (Exception e)
    {
        Assert.Fail(
            string.Format("Unexpected exception of type {0} caught: {1}",
                                e.GetType(), e.Message));
    }
}

11. 如何將依賴文件夾拷貝到輸出Bin目錄下

*.csproj 中 <ItemGroup></ItemGroup> 中設置 <CopyToOutputDirectory> 屬性

//<CopyToOutputDirectory>包含三種值
//1. Never
//2. Always
//3. PreserveNewest
<ItemGroup>
    <None Include="App.config" />
    <None Include="NerModel\model.en.all.v1.dat">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
    <None Include="NerModel\model.zh.v1.dat">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
  </ItemGroup>

12. ”mscorlib.pdb not loaded" yet the mscorlib.dll is NOT missing

Goto Tools, Options, Debugging, General, Enable Just My Code

This will prevent the debugger from trying to launch on a Internal .NET framework Assembly.

13. readonly 和 const 的區別

1. readonly 為運行時常量,程序運行時給其賦值,初始化都便無法更改。readonly 只能用來修飾類的字段(包括實例類型和靜態類型),可以在聲明的同時初始化或者在構造函數里初始化。

2. const 為編譯時常量,在編譯過程中直接被替換成字面量,使得其取值范圍只能是數字(整數、浮點數)、字符串以及枚舉類型。不僅可以聲明為類字段,還可以聲明為方法中的局部常量,默認為靜態類型(無需用static修飾,否則將導致編譯錯誤),但必須在聲明的同時完成初始化。

3. 在可維護性方面,readonly 以引用的形式工作,某個常量更新后所有用到這個常量的地方都能得到更新值。但是 const 在跨程序集里使用時,除了要將包含 const 變量的程序集重新編譯,還需要將引用到這個變量的其他程序集重新編譯才能生效。

4. 在性能方面,由於 const 是直接將字面值進行編譯參與運算,性能略高於 readonly,但是對一般的應用來說,這樣的性能提升可以忽略不計。

5. 一般情況下,只有在常量值恆久不變(圓周率、一天包含的小時數)和對程序性能要求嚴格的情況下使用 const,其他情況下使用 readonly 更合適。比較C#中的readonly與const

14. 枚舉類型

枚舉類型提供了一種有效的方式來定義可能分配給變量的一組已命名整數常量。通過Enum.ToString("G")可以返回其對應的字符串值,即其命名。

enum Day { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday };
enum Month : byte { Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec };

15. 項目依賴和編譯順序

在一個解決方案中項目的編譯順序是由依賴關系自動生成的,通過改變依賴關系來影響編譯順序。Solution -> Right Click -> Project Build Order。

Rebuild 一個解決方案的過程中,所有項目中的 CopyToOutputDirectory 指定的文件都會復制到所有項目的輸出目錄中。但是需要注意的是,再之后如果單獨編譯某個項目(build 增量編譯),那么其沒有依賴的項目中復制過來的文件會被認為是多余文件被抹去,添加項目依賴后才會保持。(因為在編譯輸出的過程中,如果輸出目錄中已經包含同名文件,那么后進行拷貝的文件就不會繼續進行)

點擊項目 build:只有在對項目文件進行更改時,點擊 build 會單獨進行該項目的編譯,否則不會作任何動作。如果依賴項發生變化也會導致依賴項和當前項目一起重新編譯,避免由於輸入變化產生的沖突。項目編譯其實生成的是一個 dll 動態鏈接庫文件,刪除之后會導致該項目重新編譯。輸出文件夾其他拷貝過來的文件刪除后不會重新編譯。

點擊項目 rebuild:Rebuild 當前項目會導致其依賴項整體重新編譯。

16. 項目之間項目引用無效

可能項目基於的框架版本不同導致的,.NET framework 版本必須一致。

17. 測試單元無法調用動態鏈接庫(在輸出目錄中存在)

測試單元使用處理器的設置與 .dll 文件的版本不同。Test -> Test Setting -> Default Proccessor Architecture -> X64。

18. Azure 項目及追蹤日志

1. Azure 項目

如果要將當前的 WebAPI 項目布到 Azure 上,需要在解決方案里新建一個 Azure Web 項目,然后將對應的 WebAPI 加入成對應的 Web Role 即可從 Azure 項目啟動。本地啟動時需要下載 Azure 環境的 Emulator,Storage Emulator 打開應用程序會自動運行,Compute Emulator 在啟動 Azure 項目時會運行。本地調試 Azure 項目時可能會遇到無法啟動的情況,一種解決方式是對IIS進行一些設置(Control Panel -> Programs and Features -> Turn Windows features on or off -> 打開一些 IIS 功能 或者 win + R -> inetmgr 打開 IIS Manager 將 Application Pools 的 Identity 改成 LocalSystem),另一種解決辦法是直接用 Administrator 權限運行 VS。

2. 追蹤日志

使用 System.Diagnostics.Trace 產生診斷信息,使用 Microsoft.WindowsAzure.Diagnostics.DiagnosticMonitorTraceListener 追蹤信息,會自動將信息存儲在 Storage Account 的 WADLogsTable 當中。(本地調試可能轉入 Table 方面不太准確,可以通過程序的 Output 進行查看)另外,需要在 Azure 的 Web Role 設置 Diagnostics 的相關配置,包括存儲周期以及日志等級。在 Web.config 加入 DiagnosticMonitorTraceListener 如下:

<system.diagnostics>
    <trace>
      <listeners>
        <add type="Microsoft.WindowsAzure.Diagnostics.DiagnosticMonitorTraceListener, Microsoft.WindowsAzure.Diagnostics, Version=2.8.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
          name="AzureDiagnostics">
          <filter type="" />
        </add>
      </listeners>
    </trace>
  </system.diagnostics>

19. HttpRequestMessage 內容體

By design the body content in ASP.NET Web API is treated as forward-only stream that can be read only once. The first read is being done when Web API is binding the Request, after that the Request.Content will not return anything. What if we want to load the Content?

第一種方式:將 Web API 方法里的對象參數去掉,只留下 Url 參數,然后手動的從 Request 中加載 Content。

第二種方式:添加一個繼承於 DelegatingHandler 的 MessageHandler,在請求送達 Web API 之前把內容讀出來,然后 Web API 綁定時會自動重置 stream 讀出對應的內容。

其他方式:采用流操作的方式,比如 await request.Content.LoadIntoBufferAsync()。參考

20. Async/Await - Best Practices in Asynchronous Programming

Async/Await - Best Practices in Asynchronous Programming

  知乎:當我們討論線程安全時,在討論什么?

21. Stream Object

流操作是先寫到 IO 緩存區,然后 flush 到硬盤上,因此如果沒有 flush 完程序就結束了,會導致部分輸出缺失。可以用 using 的方式給定作用域,能自動的 flush 和關閉流,並且 dispose。

// Example #4: Append new text to an existing file.
        // The using statement automatically flushes AND CLOSES the stream and calls 
        // IDisposable.Dispose on the stream object.
        using (System.IO.StreamWriter file = 
            new System.IO.StreamWriter(@"C:\Users\Public\TestFolder\WriteLines2.txt", true))
        {
            file.WriteLine("Fourth line");
        }

22. Console Code Page

在英文系統中,Console 的默認代碼頁是 437(OEM -United States),不支持中文輸入輸出,這與 Visual Studio 無關,與 Console 系統設置有關。通過 Win + R 打開注冊表編輯器(regedit),修改HKEY_CURRENT_USER\Console 下對應的控制台(包含 Visual Studio 控制台),增加 DWORD Value,CodePage 為 936(Simplified GBK) 即可。也可以增加 String,AutoRun 為 chcp 936。

23. 訪問權限修飾符

public:對任何類和成員都公開,無限制訪問。

protected:僅僅對該類和其派生類公開。

private:僅僅對該類公開。

internal:只能在包含該類的程序集中訪問該類(只是單獨的項目,而不是整個解決方案)。

protected internal:只能在本類,派生類或者包含該類的程序集中訪問。

代碼風格和Tips

1. 大括號的回括和下面代碼之間加一個空行。

2. 代碼中不要出現單獨的數字或者字符串,很難維護而且含義不明,用常量替代。

  3. 盡可能復用現有的數據結構。

  4. 避免在一個類中聲明另一個類的實例,降低不同類的耦合性,通過接口和構造函數傳遞參數。

  5. 同一個類不同方法之間空一行,數據成員和屬性之間不用空行。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM