在C#中删除预编译器指令

时间:2011-03-18 14:55:45

标签: c# .net-3.5 c#-3.0 compiler-directives

我被要求保留一些不像遗产一样的代码,并且它充满了编译器指令,使其几乎不可读并且几乎可维护。一个很好的例子:

#if CONDITION_1
        protected override void BeforeAdd(LogEntity entity)
#else
        protected override void BeforeAdd(AbstractBusinessEntity entity)
#endif
        {
#if CONDITON_1
            entity.DateTimeInsert = DateTime.Now;
#else
            ((LogEntity) entity).DateTimeInsert = DateTime.Now;
#endif
            base.BeforeAdd(entity);
        }

using指令甚至更漂亮:

#if CONDITION_1
using CompanyName.Configuration;
#endif

#if CONDITION_2||CONDITION_1
using CompanyName.Data;
using CompanyName.Data.SqlBuilders;
#else
using CompanyName.Legacy.Database;
using CompanyName.Legacy.Database.SQLBuilders;
using CompanyName.Legacy.Database.SQLBuilders.parameterTypes;
#endif

我以为我会给ConditionalAttribute一个但是在这种情况下不会有效

有什么方法可以解决这个编译指令的噩梦吗?

代码是针对.NET 3.5编译的。

更新
Oded回答建议删除围绕BeforeAdd方法的编译器指令,从而使其超载。遗憾的是,这两种方法都不会起作用,因为两个方法都应该覆盖AbstractBusiness类,它提供了两种不同的实现,具体取决于最终包含哪些程序集:

protected virtual void BeforeAdd(TEntity entity) {}

protected virtual void BeforeAdd(AbstractBusinessEntity entity) {}

此代码从过去某个时间创建的一组库中获取其依赖关系,并且从那时起一直在“升级”。他们现在有4个不同版本的库,其中包含冲突的命名空间和不同的实现。所有这些都与使用(非常)旧版本的应用程序的“向后兼容性”有关。


结论

我最终选择了@Oded的答案,因为它最有意义作为一般方法(K.I.S.S.以及所有这些)。但是我不能在这种情况下使用它;你在这里看到的只是冰山一角。我不想要K.I.S.S.如果它付给我这个代码。

4 个答案:

答案 0 :(得分:7)

在第一种情况下,看起来您可以简单地使用该方法的几个重载而不是此构造。此时,重载解决方案应该处理好事情。

在第二种情况下(使用指令) - 您可以使用所需的别名为一些指令添加别名并包含所有指令。包含所有名称空间后会发生什么?任何名称冲突?

答案 1 :(得分:2)

我声称这个问题不属于本课程。这个班只是一个症状。问题出在调用BeforeAdd的基类中。如果你可以在那里重构,那么你将不需要条件编译。

如果您的名称和名称空间有冲突,可以使用using关键字(而不是程序集)来解决这个问题。

所以你可以做点什么

using LegacyLogEntity = Some.Fully.Qualified.Namespace.LogEntity;
using SomeOtherLogEntity = Some.Other.Fully.Qualified.Namespace.CurrentLogEntity;

// ..
LegacyLogEntity entity = new LegacyLogEntity();

我也认为问题出在基类中,而不是本类中的问题。

在那种情况下,你可以通过使用适应或接口来解决这个废话。

我不知道其他类叫什么,但是我们说它叫做EntityAggregator。

public interface IEntity {
    DateTime InsertionTime { get; set; }
}

然后在你的聚合器基类中:

protected virtual void BeforeAdd(IEntity entity)
{ // whatever
}

然后在你的子类中:

protected override void BeforeAdd(IEntity entity)
{
    entity.DateTime = DateTime.Now;
    base.BeforeAdd(entity);
}

现在,您可以通过实现该接口来使其他对象适应IEntity。

当我查看这段代码时,我也觉得你可能正在使用事件代替这段代码。

现在,如果您正在讨论多次使用编译,其中代码在两个不同的条件下在两个不同的位置进行编译,那么您可以通过使用部分类来更优雅地进行编译。

您将CONDITION_1代码隔离为以下内容:

// in file WhateverYourClassIs.condition1.cs
#if !CONDITION_1
#error this file should never be included in a build WITHOUT CONDITION_1 set
#endif

public partial class WhateverYourClassIs {
    protected override void BeforeAdd(LogEntity entity) {
        entity.DateTimeInsert = DateTime.Now;
        base.BeforeAdd(entity);
    }
}

// in file WhateverYourClassIs.NotCondition1.cs

#if CONDITION_1
#error this file should never be included in a build WITH CONDITION_1 set
#endif

public partial class WhateverYourClassIs {
    protected override void BeforeAdd(AbstractBusinessEntity entity) {
        ((LogEntity)entity).DateTimeInsert = DateTime.Now;
        base.BeforeAdd(entity);
    }
}

在这种情况下我不喜欢这样,因为代码重复。您可以使用using关键字来帮助解决这个问题:

#if CONDITION_1
using MyAbstractBusinessEntity = LogEntity;
#else
using MyAbstractBusinessEntity = AbstractBusinessEntity;
#endif

// ...

protected override void BeforeAdd(MyAbstractBusinessEntity entity)
{
    // in CONDITION_1, the case is a no-op
    ((LogEntity)entity).DateTimeInsert = DateTime.Now;
    base.BeforeAdd(entity);
}

答案 2 :(得分:1)

根据我所看到的情况,原来的开发人员似乎没有任何继承感和多态性。从代码中分辨出来有点困难,但似乎LogEntity和AbstractBusinessEntity共享公共属性。是继承模型还是两个完全不相关的类?如果它们不相关,您可以创建一个继承模型或它们都可以实现的接口吗?如果你粘贴了这些课程可能会有所帮助。

长话短说,我不会浪费时间尝试以当前形式使用该代码。我会不惜一切代价找到消除编译器指令的方法。它看起来并不是完全不可挽救的,但可能需要一些努力。

答案 3 :(得分:0)

我不知道它是否实用,但我会做的是在我的DVCS Mercurial中创建分支来处理这个问题。

我会有2个分支在玩,而第3个暂时在我修复bug /添加常见的代码。

以下是我将如何创建初始版本:

              5---6---7         <-- type 1 of library
             /
1---2---3---4
             \
              8---9--10         <-- type 2 of library

只修复其中一个错误:

              5---6---7--11     <-- bugfix or change only to type 1
             /
1---2---3---4
             \
              8---9--10

修复常见的错误:

              5---6---7--11--13--15    <-- merged into type 1
             /                   /
1---2---3---4--11--12---+-------+      <-- common fix(es)
             \           \
              8---9--10--14            <-- merged into type 2

注意:这假设您不会在任何类型或公共分支中进行严厉的重构,如果您这样做,您可能会更好地了解您当前的情况,至少与这样的分支方式相比。任何这样的重构都会使未来的合并真的痛苦。