C#!条件属性?


69

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 不是正确的,但足够真实。不要让我带回Nitpicker的角落。 🕗


8
不。请注意,这[Conditional(...)]并不等同于此。它也删除了呼叫站点。
SLaks

1
@SLaks:我正在写一个包含这一点的答案:)
Jon Skeet

1
似乎是一个有用的功能。:打开一个关于它的功能要求在GitHub上github.com/dotnet/csharplang/issues/2742
МаксимКошевой

Answers:


56

首先,具有Conditional属性并不等于#if在方法内部具有属性。考虑:

ShowDebugString(MethodThatTakesAges());

由于的真实行为ConditionalAttribute,因此MethodThatTakesAges不会被调用-包括参数评估在内的整个调用都将从编译器中删除。

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

但是不,我不相信有什么可以满足您的需求。我刚刚检查了涉及条件方法和条件属性类的C#spec部分,并且没有任何内容暗示存在这种机制。


1
您可以干净地找到的最接近的是以下SLAKS解决方案。
凯文·斯特雷彻

48

不。

相反,您可以编写

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

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


2
这实际上是最好的解决方案,但是我强烈建议您使用长随机哈希而不是FALSE(可以在某些程序集中进行设置)。
凯文·斯特雷彻

通常它会起作用,但有一些警告。在回调中使用属性方法时,此代码将无法编译。
Uldis Valneris

18

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

// at the begining of the code before uses
#if DUMMY
#undef NOT_DUMMY
#else
#define NOT_DUMMY
#endif

// somewhere in class
[Conditional("NOT_DUMMY")]
public static void ShowDebugStringNOTDUMMY(string s)
{
  Debug.Print("ShowDebugStringNOTDUMMY");
}


[Conditional("DUMMY")]
public static void ShowDebugStringDUMMY(string s)
{
  Debug.Print("ShowDebugStringDUMMY");
}

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


5
-1不错的尝试,但这并不总能奏效,因为这并不取决于调用方的编译时预处理程序符号(尤其是如果调用方在另一个程序集或同一程序集中的另一个模块上)。
Kryptos

是的,它取决于编译时所有程序集的调用者的编译器上下文(条件#if必须如c#标准所说在调用者上下文中)。从来没有说过如果将条件#if放在另一个程序集中,它是否会工作,那不是OP的问题。那么,我是否可以问为什么要投反对票呢?
SoLaR 2015年

16

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

1
你到底为什么要这样做?为什么不只使用类似的东西#if DEBUG return true; #else return false; #endif
Joep Beusenberg

3
看一下有关使用杂注标签与条件属性的优点的深入讨论。这太过分了一个评论,说明:stackoverflow.com/questions/3788605/...
Riegardt斯泰恩

我本来要写这样的东西,很高兴您为我做了,但是奇怪的是,下面的答案如此。我认为如果此代码位于不同的程序集中则不起作用,因为是否在组装时(而不是在调用时)决定是否调用“ CheckDebugMode”。从这个意义上讲,它与使用#if进行检查非常相似。
JorgeGalvão18年

有趣的是,尽管我个人还没有遇到这个问题-我尽量避免单独构建的程序集相互引用以避免DLL Hell。一种方法是将SoA与程序集之间的WCF调用一起使用。是的,答案与#if非常相似,但是这里仅是示例的众多优点之一:如果执行代码清理,则如果仅在灰色的编译指示中使用了IDE,则IDE将删除“未使用”的using子句。部分。
Riegardt Steyn,

1
现在,CLR内联了静态只读基元类型,因此,如果将bolean标志更改为静态只读,并通过反射将其设置在任何地方(例如,在Main或Application_Start等中使用)之前通过反射进行设置,则jit将完全删除方法中未使用的条件代码路径。可能只剩下return语句,方法调用将被完全消除!
TakeMeAsAGuest

4
#ifndef ShowDebugString
#define RemoveSDS
#endif

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


1
但是,这需要在调用代码中-在需要该功能的每个文件中。与IMO的要求有很大不同。
乔恩·斯基特

@JonSkeet +1提一个全球性的修复程序的价值,而不是要求每个人改变所有现有的代码(stackoverflow.com/questions/244246/c-alias-a-class-name
伊恩·博伊德

最佳解决方案可能是在项目级别添加一个新定义,该定义对于每个构建配置都具有正确/期望的值。
詹姆斯


0

我喜欢@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;
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.