C# !条件属性

本文关键字:属性 条件 | 更新日期: 2023-09-27 18:15:29

C# 是否有Conditional(!ConditionalNotConditionalConditional(!)(属性?


我知道 C# 有一个Conditional属性:

[Conditional("ShowDebugString")]
public static void ShowDebugString(string s)
{
   ...
}

相当于1 到:

public static void ShowDebugString(string s)
{
#if ShowDebugString
   ...
#endif
}

但在这种情况下,我想要相反的行为(您必须特别选择退出(:

public static void ShowDebugString(string s)
{
#if !RemoveSDS
   ...
#endif
}

这导致我尝试:

[!Conditional("RemoveSDS")]
public static void ShowDebugString(string s)
{
   ...
}

这不编译。和:

[Conditional("!RemoveSDS")]
public static void ShowDebugString(string s)
{
   ...
}

这不编译。和:

[NotConditional("RemoveSDS")]
public static void ShowDebugString(string s)
{
   ...
}

这不会编译,因为它只是一厢情愿的想法。

1 不是真的,但足够真实。不要让我带回吹毛求疵者的角落。

C# !条件属性

首先,具有 Conditional 属性并不等同于在方法中包含#if。考虑:

ShowDebugString(MethodThatTakesAges());

ConditionalAttribute的真实行为中,MethodThatTakesAges不会被调用 - 包括参数计算在内的整个调用从编译器中删除。

当然,另一点是它取决于调用方编译时的编译时预处理器符号,而不是方法:)

但是不,我不相信这里有什么可以做你想要的。我刚刚检查了处理条件方法和条件属性类的 C# spec 部分,其中没有任何内容表明存在任何此类机制。

不。

相反,你可以写

#if !ShowDebugString
[Conditional("FALSE")]
#endif

请注意,与 [Conditional] 不同,这将由程序集中符号的存在决定,而不是调用方程序集中的符号。

诚然,我们不能"不"条件属性,但我们可以"不"条件如下所示。

// at the beginning of the code before any using clauses 
// we shall negate the condition.
#if DUMMY
#undef NOT_DUMMY
#else
#define NOT_DUMMY
#endif
using System;
using System.Diagnostics; // required by ConditionalAttribute 
namespace Demonstration
{
  public static class NotCondition
  {
    /// <summary>
    /// The following method is called when 'DUMMY' is defined in project settings
    /// </summary>
    [Conditional("DUMMY")]
    static void ShowDebugStringDUMMY(string s)
    {
      Debug.WriteLine($"called {nameof(ShowDebugStringDUMMY)}({s})");
    }
    /// <summary>
    /// The following method is called when 'DUMMY' is not defined in project settings
    /// </summary>
    [Conditional("NOT_DUMMY")]
    static void ShowDebugStringNOTDUMMY(string s)
    {
      Debug.WriteLine($"called {nameof(ShowDebugStringNOTDUMMY)}({s})");
    }
    /// <summary>
    /// Example that calls to methods that are included in context of conditional method as arguments shall not be executed.
    /// </summary>
    static string GetText(string s)
    {
      Debug.WriteLine($"{nameof(GetText)}({s})");
      return s;
    }
    public static void Test()
    {
      // following method is compiled 
      ShowDebugStringDUMMY(GetText("dummy"));
      ShowDebugStringNOTDUMMY(GetText("!dummy"));
    }
  }
}

现在,特定方法的编译取决于包含此文件的项目的条件编译符号的定义。

项目属性 -> 生成 -> 条件编译符号

条件编译符号

指定要对其执行条件编译的符号。用分号 (";"( 分隔符号。有关详细信息,请参阅/define (C# 编译器选项(。

如何使用演示代码:

  • 创建新的CSharp类文件并复制粘贴上面的代码;
  • 从代码中调用 Demo.NotCondition.Test((,最好在 Program.Main(( 方法的开头;
  • 并从项目设置中设置或删除"虚拟"编译条件符号,以查看行为差异;

如果我们没有在项目设置中设置编译条件符号"DUMMY",则当项目运行时,输出窗口应显示以下内容:

GetText(!dummy)
called ShowDebugStringNOTDUMMY(!dummy)

否则,如果我们在项目设置中设置了编译条件符号"DUMMY",则当项目运行时,输出窗口将显示以下内容:

GetText(dummy)
called ShowDebugStringDUMMY(dummy)
  • 注意:项目条件编译符号仅对该项目中的文件可见,对某些引用的项目文件中的文件不可见。

希望这可以帮助您解决问题;)

只是加上我的 2 美分,三年后:-(...我使用 [Conditional("DEBUG")] 方法来设置 IsDebugMode 属性来检查反向情况。哈基,但它有效:

private bool _isDebugMode = false;
public bool IsDebugMode
{
    get
    {
        CheckDebugMode();
        return _isDebugMode;
    }
}
[Conditional("DEBUG")]
private void CheckDebugMode()
{
    _isDebugMode = true;
}
private void DisplaySplashScreen()
{
    if (IsDebugMode) return;
    var splashScreenViewModel = new SplashScreenVM(500)
    {
        Header = "MyCompany Deals",
        Title = "Main Menu Test",
        LoadingMessage = "Creating Repositories...",
        VersionString = string.Format("v{0}.{1}.{2}",
            GlobalInfo.Version_Major, GlobalInfo.Version_Minor, GlobalInfo.Version_Build)
    };
    SplashScreenFactory.CreateSplashScreen(splashScreenViewModel);
}
#ifndef ShowDebugString
#define RemoveSDS
#endif

编辑:有关更多说明。 如果定义了 ShowDebugString Conditional["ShowDebugString"]将被调用。 如果未定义 ShowDebugString,则将调用Conditional["RemoveSDS"]

我喜欢@Heliac提到的方法,并为它做了一个帮助类:

class Build
{
    public static bool IsDebug { get; private set; }
    static Build()
    {
        CheckDebugMode();
    }
    [System.Diagnostics.Conditional("DEBUG")]
    static void CheckDebugMode()
    {
        IsDebug = true;
    }
}

尽管对DEBUG的用处不是立竿见影的

这允许您执行以下操作

static readonly bool UseCaching = !Build.IsDebug;

NET 框架标准库注释引用没有声明任何内容。所以恐怕你得自己滚

受到@SLaks答案的启发,我想出了以下解决方案来解决缺少否定条件的问题。请注意,就像他们的答案一样,[Conditional]的评估将取决于定义此符号的文件中存在的相应预处理器符号,而不是调用符号,这是您可能想要也可能不希望的。

这个想法是,你需要一个预处理器符号,它是在项目范围内定义的(或你定义的(,例如 NET_STANDARD .然后,您需要另一个肯定未定义的预处理器符号,例如THIS_IS_JUST_SOME_RANDOM_STRING_THAT_IS_NEVER_DEFINED。使用这些前提条件,您可以构建以下解决方法:

#if ShowDebugString
#undef HideDebugString
#else
#define HideDebugString
#endif
#define SOME_OTHER_CONDITION
public static class Conditional
{
    private const string TRUE = "NET_STANDARD"; //pick one that is always be defined in your context
    private const string FALSE = "THIS_IS_JUST_SOME_RANDOM_STRING_THAT_IS_NEVER_DEFINED";
#if ShowDebugString
    public const string ShowDebugString = TRUE;
#else
    public const string ShowDebugString = FALSE;
#endif
#if HideDebugString
    public const string HideDebugString = TRUE;
#else
    public const string HideDebugString = FALSE;
#endif
#if SOME_OTHER_CONDITION
    public const string SOME_OTHER_CONDITION = TRUE;
#else
    public const string SOME_OTHER_CONDITION = FALSE;
#endif
}

现在,您有一些可用于[Conditional]属性的const string,这些属性不需要调用方定义相应的预处理器符号。这意味着这种方法也适用于您在上述代码开头所做的任何#define(这是我所需要的(。然后,这些可用于您的方法:

[Conditional(Conditional.ShowDebugString)]
public static void ShowDebugString(string s)
{
   //...
}
[Conditional(Conditional.HideDebugString)]
public static void ShowReleaseString(string s)
{
   //...
}
[Conditional(Conditional.SOME_OTHER_CONDITION)]
public static void SomeOtherMethod()
{
   //...
}

虽然设置起来有点乏味,但这种方法的一个很好的副作用是,您可以在单独的文件中定义一次所有样板代码,以免妨碍您的主代码,或在多个位置使用它。如果你只需要(或想要(在一个地方使用该功能,你当然也可以在同一文件或类中定义所有字符串。

奖励:现在不太容易搞砸,通过在[Conditional("Attribut")]中错误键入字符串.