C# !条件属性
本文关键字:属性 条件 | 更新日期: 2023-09-27 18:15:29
C# 是否有不Conditional
(!Conditional
、NotConditional
、Conditional(!)
(属性?
我知道 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 不是真的,但足够真实。不要让我带回吹毛求疵者的角落。
首先,具有 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")]
中错误键入字符串.