C # ! 条件属性?

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 不是真的,但足够真实。不要让我带回挑剔者的角落。 < sup > 🕗

29350 次浏览

首先,拥有 Conditional属性等价于在方法中拥有 #if:

ShowDebugString(MethodThatTakesAges());

对于 ConditionalAttribute的实际行为,MethodThatTakesAges不会被调用——整个调用 包括论点评估将从编译器中删除。

当然,另一点是它依赖于 打电话的人编译时的编译时预处理器符号,而不是 方法:)

但是,我不相信这里有任何东西能达到你的目的。我刚检查了 处理条件方法和条件属性类的 C # spec 部分没有任何迹象表明有这种机制。

NET 框架标准库注释引用没有说明,所以恐怕你得自己卷了!

#ifndef ShowDebugString
#define RemoveSDS
#endif

编辑: 以便进一步澄清。如果定义了 ShowDebugString,则将调用 Conditional["ShowDebugString"]。如果未定义 ShowDebugString,则将调用 Conditional["RemoveSDS"]

没有。

相反,你可以写作

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

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

只要加上我的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);
}

的确,我们不能‘ NOT’ConditionalAttribute,但是我们可以‘ NOT’条件,如下所示。

// 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"));
}
}
}

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

项目属性-> 建置-> 条件编译符号

条件编译符号

指定要对其执行条件编译的符号。 用分号(“ ;”)分隔符号。有关更多信息,请参见 定义(C # 编译器选项)。

如何使用演示代码:

  • 创建新的 CSharp 类文件,并复制粘贴上述代码;
  • 从您的代码中调用 Exploration.NotCondition.Test () ,最好是在 Program.Main ()方法的开头;
  • 从项目设置中设置或删除“ DUMMY”编译条件符号,查看行为差异;

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

GetText(!dummy)
called ShowDebugStringNOTDUMMY(!dummy)

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

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

希望这能帮助你解决问题;)

我喜欢@Heliac 提到的方法,并为其创建了一个 helper 类:

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;

受到@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
}

现在您有了一些 const string,可以用于 [Conditional]属性,它们不需要调用方定义相应的预处理器符号。这意味着这种方法也适用于您在上面代码开始时创建的任何 #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")]中输入错误的字符串就不那么容易搞砸了。