Getting rid of precompiler directives in C#

回眸只為那壹抹淺笑 提交于 2019-12-05 07:19:01

In the first case, it looks like you could simply have several overloads of the method instead of this construct. Overload resolution should take care of things at this point.

In the second case (using directives) - you can alias some of the directives and include all of them, using the alias where needed. What happens when all namespaces are included? Any name collisions?

I'd claim that the problem isn't in this class. This class is just a symptom. The problem is in the base class that's calling BeforeAdd. If you can refactor there, then you won't need the conditional compiles.

If you have conflicting names and namespaces, you can work around that with the using keyword (not the one for assemblies).

So you can do something like

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

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

I also think that the problem is in the base class, not in this class, per se.

In that event you can get around this nonsense by using either adaptation or interfacing.

I don't know what the other class is called, but let's say that it's called an EntityAggregator.

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

then in your aggregator base class:

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

then in your subclass:

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

Now you can adapt the other objects to be IEntity by implementing that interface.

When I look at this code, it also strikes me that maybe you be using events instead of this code.

Now if you're talking about multiple use compilation, where the code is being compiled in two separate places under two different conditions, then you can do that more gracefully by using partial classes.

You isolate the CONDITION_1 code into something like this:

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

I don't like this in this case because of code repetition. You can help this with use of the using keyword:

#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);
}

Based on what I'm seeing, it seems the original developer didn't have any sense of inheritance and polymorphism. It's a little difficult to tell from the code, but it seems LogEntity and AbstractBusinessEntity share common properties. Is there an inheritance model or are they two completely unrelated classes? If they are unrelated, could you create an inheritance model or an interface they can both implement? It might help if you pasted the classes.

Long story short, I wouldn't waste my time trying to work with that code in its current form. I'd find a way to eliminate the compiler directives, at all costs. It doesn't look to be completely un-salvageable, but it might take some effort.

I don't know if it is practical, but what I would do would be to create branches in my DVCS, Mercurial, to handle this.

I would have 2 branches in play, and a 3rd temporarily while I fix bugs/add code that is common.

Here's how I would create the initial versions:

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

To fix bugs in only one of them:

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

To fix bugs that are common:

              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

Note: This assumes you're not going to make heavy-handed refactoring in either type or common branches, if you do that, you're probably better off with your current situation, at least compared to a branchy way like this. Any such refactoring would make future merges really painful.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!