因為現在 .net 版本比較多,但不是所有 .net 版本都可以向下兼容(具體可參見:https://docs.microsoft.com/zh-cn/dotnet/standard/net-standard)
但有一些公共純邏輯與平台無關代碼希望能夠可以打包為 nuget 包,被各種項目引用。甚至即便與平台相關,但是可以根據不同平台進行不同實現的需求。
以下以 .net framework 4 和 .net standard 2.0 項目共享為例,實際可以擴展到任意 .net 版本:
1、使用 .net standard 2.0 創建一個類庫項目
盡量使用高版本 .net 框架(通過 PackageReference 管理引用)進行創建來兼容低版本的(通過 package.config 管理引用)
低版本也不是不能改,就是需要從 package.config 遷移到 PackageReference,就更復雜了
參考文檔:https://docs.microsoft.com/zh-cn/nuget/consume-packages/package-references-in-project-files
2、新建項目后,在解決方案管理器的項目上點右鍵,選擇編輯項目文件
3、在打開的項目文件中,將原有的 TargetFramework 節點替換為 TargetFrameworks,然后在節點中增加需要的目標框架,改完如下所示:
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <!-- 聲明需要的目標框架 --> <TargetFrameworks>netstandard2.0;net40</TargetFrameworks> </PropertyGroup> <!-- 通過條件輸出注釋文件到不同路徑 --> <PropertyGroup Condition="'$(Configuration)'=='Release'"> <DocumentationFile>bin\Release\$(TargetFramework)\$(MSBuildProjectName).xml</DocumentationFile> </PropertyGroup> <!-- 在 .NET Framework 4.0 目標框架下需要引用的項目 --> <ItemGroup Condition="'$(TargetFramework)' == 'net40'"> <Reference Include="System.Net" /> <COMReference Include="NetFwTypeLib"> <Guid>{58FBCF7C-E7A9-467C-80B3-FC65E8FCCA08}</Guid> <VersionMajor>1</VersionMajor> <VersionMinor>0</VersionMinor> <Lcid>0</Lcid> <WrapperTool>tlbimp</WrapperTool> <Isolated>False</Isolated> <EmbedInteropTypes>True</EmbedInteropTypes> </COMReference> </ItemGroup> <!-- 在 .NET Standard 2.0 目標框架下需要引用的項目 --> <ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'"> <PackageReference Include="Microsoft.Windows.Compatibility" Version="5.0.2" /> </ItemGroup> </Project>
除了修改 TargetFrameworks 以外,對於未來添加的非通用的引用,都需要在 ItemGroup 下通過 TargetFrameWork 進行條件控制引用
在 VS 界面添加的引用,默認是通用的,不區分目標框架,可以在添加完成后,再編輯項目文件進行手動調整
關於項目定義文件中的可使用的變量,似乎在不同的編譯階段也不盡相同,基本都是靠參考自動生成的內容或者從網上查找相關示例。
大概查到了以下幾個文檔地址:
MSBuild:
https://docs.microsoft.com/zh-cn/visualstudio/msbuild/msbuild-properties
https://docs.microsoft.com/zh-cn/visualstudio/msbuild/msbuild-reserved-and-well-known-properties
4、到此為止,也就完成了項目的多目標框架配置,可以在項目依賴項中看到多目標框架的各自引用內容:
在編輯源代碼時,可以通過左上角切換不同的目標框架,以檢查代碼的錯誤:
不知道為什么沒有在 VS 界面中實現以上需要手動配置的復雜操作,也許是邏輯太復雜了嗎。。。
5、最后就是在代碼中,如果需要有針對各自平台的邏輯,可以通過 #if … #endif 編譯條件進行判斷屏蔽
在不同目標框架下,預設的條件也不同,但需要注意的是,這里的條件僅代表目標框架,並不表示實際運行平台(比如 Windows 或 Linux),對於平台邏輯的判斷還需要額外進行判斷。
參考文檔:https://docs.microsoft.com/zh-cn/dotnet/core/tutorials/libraries#how-to-multitarget