【问题标题】:Is conditional compilation bad practice when targeting .NET Standard and .NET Framework? [closed]以 .NET Standard 和 .NET Framework 为目标时,条件编译是不好的做法吗? [关闭]
【发布时间】:2020-10-19 16:53:27
【问题描述】:

我一直认为条件编译是不好的做法,除非你无法避免。又名 #ifdefhell 见https://www.cqse.eu/en/news/blog/living-in-the-ifdef-hell/

我很惊讶微软似乎在没有评论或说明应该避免的情况下鼓励这样做。见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

是否应该避免条件编译?还是完全可以使用?对我来说很明显,由于重复代码、测试困难和维护代码库的复杂性,最好避免这种情况。然而,看到 Microsoft 文档后,我对自己的断言提出了质疑。

【问题讨论】:

  • Microsoft 不断更改每个版本的 Net 的默认选项。例如安全类,他们使用最新/最好的加密模式作为默认值。因此,如果您想要向后兼容,您可能需要使用条件编译。然后,当 Microsoft 在 Net 4.0 中为 SMTP 从 Net 3.5 升级到 Net 4.0 时,您需要添加 Net 3.5 中没有的 DefaultCredentials。

标签: c# .net compilation .net-standard .net-framework-version


【解决方案1】:

嗯,你可能一开始就不应该多目标,除非你正在编写一个绝对(不是可能,但绝对!)用于支持遗留项目的库。今天,没有理由不编写 .Net5 代码,除非您正在编写 UWP/Xamarin 应用程序。

但是,如果您是多目标,则需要编写可在所有目标下编译的代码。这涉及 #if 和 MsBuild 目标项目,以有条件地包含整个源代码文件。

【讨论】:

    【解决方案2】:

    我一直认为条件编译是不好的做法除非你无法避免

    没错。多目标是无法避免的情况之一。

    .NET 的不同版本和风格之间的 API 是不同的,因此要以跨不同目标的方式执行相同的操作,您必须引用不同的程序集并调用仅存在于某些程序集中的 API,但不在别人身上。

    在某些情况下,您甚至没有替代 API,并且条件编译将仅用于抛出 NotSupportedException 或类似内容。

    条件编译对于代码本身以及 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>
    

    也就是说,您可以将条件编译指令推送到堆栈的越远,它就越容易维护。

    创建(或使用现有的)调用较低级别 API 的抽象将有助于避免在您的应用代码中使用条件编译指令。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-29
      • 2019-11-03
      相关资源
      最近更新 更多