以 .NET Standard 和 .NET Framework 为目标时,条件编译是不好的做法吗?
Is conditional compilation bad practice when targeting .NET Standard and .NET Framework?
我一直认为条件编译是不好的做法,除非你无法避免。又名 #ifdefhell 请参见 https://www.cqse.eu/en/news/blog/living-in-the-ifdef-hell/
令我惊讶的是,Microsoft 似乎在某种程度上鼓励这种做法,但没有发表评论或指出应该避免这种做法。参见 https://docs.microsoft.com/en-us/dotnet/core/tutorials/libraries#how-to-multitarget
using System;
using System.Text.RegularExpressions;
#if NET40
// This only compiles for the .NET Framework 4 targets
using System.Net;
#else
// This compiles for all other targets
using System.Net.Http;
using System.Threading.Tasks;
#endif
是否应该避免条件编译?还是完全可以接受使用?对我来说很明显,由于代码重复、测试困难和维护代码库的复杂性,最好避免这样做。然而,看到微软文档后,我对自己的断言提出了质疑。
嗯,您可能一开始就不应该 multi-target,除非您编写的库绝对(不是可能,但绝对!)用于支持遗留项目。今天,没有理由不编写 .Net5 代码,除非您正在编写 UWP/Xamarin 应用程序。
但是,如果您 multi-targetting,则需要编写可在所有目标下编译的代码。这涉及 #if
和 MsBuild 目标项目,有条件地包括整个源代码文件。
I've always seen conditional compilation as bad practice unless you can't avoid it.
没错。 Multi-targeting 是无法避免的情况之一。
不同版本和风格的 .NET 之间的 API 是不同的,因此要以适用于不同目标的方式做同样的事情,您必须引用不同的程序集并调用 APIs 仅存在于某些程序集中,但不存在于其他程序集中。
在某些情况下,您甚至没有替代方案 API,条件编译将仅用于抛出 NotSupportedException
或类似的。
条件编译对于 multi-targeting 代码本身以及 MSBuild 脚本(例如,决定引用哪些程序集)都至关重要:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard1.4;net40;net45</TargetFrameworks>
</PropertyGroup>
<!-- Need to conditionally bring in references for the .NET Framework 4.0 target -->
<ItemGroup Condition="'$(TargetFramework)' == 'net40'">
<Reference Include="System.Net" />
</ItemGroup>
<!-- Need to conditionally bring in references for the .NET Framework 4.5 target -->
<ItemGroup Condition="'$(TargetFramework)' == 'net45'">
<Reference Include="System.Net.Http" />
<Reference Include="System.Threading.Tasks" />
</ItemGroup>
</Project>
也就是说,您可以将条件编译指令下推到堆栈的下方,维护起来就越容易。
创建(或使用现有的)调用 lower-level API 的抽象将有助于避免在您的应用代码中出现条件编译指令。
我一直认为条件编译是不好的做法,除非你无法避免。又名 #ifdefhell 请参见 https://www.cqse.eu/en/news/blog/living-in-the-ifdef-hell/
令我惊讶的是,Microsoft 似乎在某种程度上鼓励这种做法,但没有发表评论或指出应该避免这种做法。参见 https://docs.microsoft.com/en-us/dotnet/core/tutorials/libraries#how-to-multitarget
using System;
using System.Text.RegularExpressions;
#if NET40
// This only compiles for the .NET Framework 4 targets
using System.Net;
#else
// This compiles for all other targets
using System.Net.Http;
using System.Threading.Tasks;
#endif
是否应该避免条件编译?还是完全可以接受使用?对我来说很明显,由于代码重复、测试困难和维护代码库的复杂性,最好避免这样做。然而,看到微软文档后,我对自己的断言提出了质疑。
嗯,您可能一开始就不应该 multi-target,除非您编写的库绝对(不是可能,但绝对!)用于支持遗留项目。今天,没有理由不编写 .Net5 代码,除非您正在编写 UWP/Xamarin 应用程序。
但是,如果您 multi-targetting,则需要编写可在所有目标下编译的代码。这涉及 #if
和 MsBuild 目标项目,有条件地包括整个源代码文件。
I've always seen conditional compilation as bad practice unless you can't avoid it.
没错。 Multi-targeting 是无法避免的情况之一。
不同版本和风格的 .NET 之间的 API 是不同的,因此要以适用于不同目标的方式做同样的事情,您必须引用不同的程序集并调用 APIs 仅存在于某些程序集中,但不存在于其他程序集中。
在某些情况下,您甚至没有替代方案 API,条件编译将仅用于抛出 NotSupportedException
或类似的。
条件编译对于 multi-targeting 代码本身以及 MSBuild 脚本(例如,决定引用哪些程序集)都至关重要:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard1.4;net40;net45</TargetFrameworks>
</PropertyGroup>
<!-- Need to conditionally bring in references for the .NET Framework 4.0 target -->
<ItemGroup Condition="'$(TargetFramework)' == 'net40'">
<Reference Include="System.Net" />
</ItemGroup>
<!-- Need to conditionally bring in references for the .NET Framework 4.5 target -->
<ItemGroup Condition="'$(TargetFramework)' == 'net45'">
<Reference Include="System.Net.Http" />
<Reference Include="System.Threading.Tasks" />
</ItemGroup>
</Project>
也就是说,您可以将条件编译指令下推到堆栈的下方,维护起来就越容易。
创建(或使用现有的)调用 lower-level API 的抽象将有助于避免在您的应用代码中出现条件编译指令。