C# 条件代码的更好方法

C# 条件代码的更好方法,c#,conditional-compilation,C#,Conditional Compilation,我有一些在中定义了大量常量的代码,如果调试#else块;比如: public static class C { #if DEBUG public const string FIELDAAA = "VeryLongDescriptiveFieldName"; public const string FIELDBBB = "AnotherLongDescriptiveFieldName"; public const string FIELDCC

我有一些在
中定义了大量常量的代码,如果调试#else
块;比如:

public static class C
{
    #if DEBUG
        public const string FIELDAAA = "VeryLongDescriptiveFieldName";
        public const string FIELDBBB = "AnotherLongDescriptiveFieldName";
        public const string FIELDCCC = "YetAnotherLongFieldName";

        // ... many more field definitions
    #else
        public const string FIELDAAA = "F1";
        public const string FIELDBBB = "F2";

        // Notice that FIELDCCC is missing - whoever added it to the
        // DEBUG block, forgot to add it here.
    #endif
}
这些字段用于向第三方服务器生成文本请求-服务器可以采用任何形式的字段名。不过,使用短格式要有效得多,因为每条消息都有大小限制,当请求太大时,必须将其分解为多条消息。每个消息都有成本,因此我们的软件应该在生产中使用短字段名,在开发过程中使用长字段名(用于调试)

此设置有许多源文件,其中大多数在调试块和else块中具有不匹配的常量。由于这些不匹配,由于缺少常量,此应用程序的某些部分无法在发布模式下构建

我试图通过删除巨大的
DEBUG
块来解决这个问题,但我需要保留长字段名和短字段名定义,同时确保很难错误地添加新字段名。我还希望将更改的数量保持在最低限度-这是在一个由许多用户使用的大型应用程序中,我不想引入突破性的更改-这些字段在许多地方使用

目前我的想法是:

public static class C
{
    public const string FIELDAAA =
        #if DEBUG
        "VeryLongDescriptiveFieldName";
        #else
        "F1";
        #endif

    public const string FIELDBBB = 
        #if DEBUG
        "AnotherLongDescriptiveFieldName";
        #else
        "F2";
        #endif

    public const string FIELDCCC = 
        #if DEBUG
        "YetAnotherLongFieldName";
        #else
        "F3";
        #endif

    // more constants
}
我不知道我是否有精神障碍,但我想不出比这更好的了。有没有更好的方法可以让我在不太混乱的情况下完成我想做的事情?我在使用
#if DEBUG
时没有问题,但这感觉很脏,如果有更干净的解决方案,我更喜欢。

是的,有!!。(始终)

我想你可以使用类似工厂模式()的东西,或者使用依赖注入

这样,您应该删除公共静态C类,并且可以使用下面这样的另一个解决方案

通过这种方式,您不必将解决方案仅与#if调试每个字符串绑定,并且使用工厂模式实例化“正确”的常量,这样您就不必担心每个字符串之间的冲突

您的代码将被编译,因为接口要求每个类正确地实现,并且没有集合的属性将不允许程序员更改内容

在使用常数的类中,您可以执行以下操作

public class UsingClass
{
    IConstantClass constants;
    public UsingClass(){
         constants f = new FactoryConstants();
    }
}

public class FactoryConstant
{
   public FactoryConstant()
   {
   }
   public IConstantClass GetConstant()
   {
       #if DEBUG
       return new ConstantsDebugMode();
       #else
       return new ConstantsProduction();
       #endif
   }
}

public interface IConstantClass
{
   public string FIELDAAA {get;set;}
   public string FIELDBBB {get;set;}
} 

public class ConstantsProduction : IConstantClass
{
   public string FIELDAAA
   {
       get { return "ProductionString"; }
       set { }
   }
   public string FIELDBBB
   {
       get { return "ProductionString2"; }
       set { }
   }
}

public class ConstantsDebugMode : IConstantClass
{
   public string FIELDAAA
   {
       get { return "ReallyLongStringDebugMode"; }
       set { }
   }
   public string FIELDBBB
   {
       get { return "ReallyLongStringDebugMode2222"; }
       set { }
   }
}
注:我没有测试这段代码,但它应该可以工作

依赖注入解决方案将在配置文件中配置系统应如何实现接口类(IConstantClass),因此无需每次实例化Factory类


您可以更改我的代码,并使用正确的解决方案将接口传递给构造函数中的类或属性。

您可以从资源文件中读取接口,并使用不同的文件进行调试。据我所知,没有什么比这更好的了。您的解决方案结束了缺少常量的问题,因为如果更改后有人“忘记”add都是constanst,那么他最好改变工作。我想他可能需要变量为
const
。如果不是这样,这是好的。我对你的答案投了赞成票,但我仍在考虑是否应该接受。我在开始时考虑过这种方法,但一开始就放弃了它,因为它需要大量的设置来获得我想要的收益请看“有问题”。在您的回答之后,我对它进行了另一个思考-很明显,它需要比
const
方法更多的设置。它确实提供了更多的灵活性,但这些点也可能成为错误点。这肯定会提供使用两组字段定义测试代码的能力(常数是不可能的-这是我最初没有想到的一个方面)。我会再考虑一点-我想看看是否出现了另一种值得考虑的方法。你需要一个初始设置,但之后你就可以“自由行动”,你可以使用一些注入依赖项框架,如Ninject()这样你只需要设置一次界面!我决定使用这种方法-正如我说的,我在提出问题之前考虑过这一点,但由于涉及到大量的设置工作,所以放弃了它。不过,测试两个不同分支的能力非常重要,所以我几次回到这一点上,只是决定咬紧牙关去做吧。