开发者

Way to eliminate pre-processor commands

I need a way to show this C# 3.0 code:

[TestMethod]
#if NUNIT
        [Moled]
#else
        [HostType("Moles")]
#endif
public void TestSomething()

With out using/needing the pre-processor commands on each method.

Is this possible?


Talking with a co-worker, we theorized that there may be a way to create an attribute class that has 2 constructors (one with zero params and one with 1 string). Then in the top of the file we do our conditional there like this:

#if NUNIT
   M开发者_如何学JAVAoled = MyNamespace.MyNewAttribute;
#else
   HostType = MyNamespace.MyNewAttribute;
#endif

The MyNewAttribute class would be setup to do nothing, so that I can compile with this:

[TestMethod]
[Moled]
[HostType("Moles")]
public void TestSomething()

Would this work? How would I write this class?


Your updated question provides an interesting and (in my opinion) viable solution.

All you need to do to finish it is to declare MyNewAttribute, which should be simple:

[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
public sealed class MyNewAttribute : Attribute
{
    public MyNewAttribute() { }
    public MyNewAttribute(string dummy) { }
}

In your #if trick, you will have to use the full class names:

#if NUNIT
   using MoledAttribute = MyNamespace.MyNewAttribute;
#else
   using HostTypeAttribute = MyNamespace.MyNewAttribute;
#endif

Note: I don’t know which way around these should be — your question contradicts itself on this. Remember you need to redefine the one that you want to disable, not the one you want to enable.

Also, these using statements need to be first within the namespace, before all type declarations. I tried this and it works even if MyNewAttribute is declared further down in the same file.

Since this is quite an unusual trick, I strongly recommend to put an explanatory comment on the #if construct so that future readers of your code can understand what it means, why it’s there, and how it works.

By the way, with custom attribute names as short as these, and with few or no constructor arguments, personally I find it more readable to put them in one line:

[TestMethod, Moled, HostType("Moles")]
public void TestSomething()


I don't see why you need aliases at all. Just do this in one single file:

#if NUNIT

[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
public sealed class HostTypeAttribute : Attribute
{
    public HostTypeAttribute(string dummy) { }
}

#else

[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
public sealed class MoledAttribute : Attribute
{
    public MoledAttribute() { }
}

#endif

Then you can use both, in any file, with no preprocessor defines anywhere except here.


You are close to the right track. You just need to create a dummy attribute class that can take the place of the attributes that you are trying to switch:

public sealed class DummyAttribute : Attribute
{
    public DummyAttribute()
    {}

    pulic DummyAttribute(string dummy)
    {}
}

The two constructors are necessary because one of the attributes that you are trying to replace accepts a string as a parameter. Setting up the dummy constructors allows you to ignore the actual behavior of the attributes that you are replacing.

Then your preprocessor block at the top of the file should look something like this:

#if !NUNIT
using Moled = MyNameSpace.DummyAttribute;
#else
using HostType = MyNameSpace.DummyAttribute;
#endif


Sure, split it into two files:

File1:

[TestMethod]  
[Moled]  
public void TestSomething()

File2:

[TestMethod]  
[HostType("Moles")]  
public void TestSomething()

Use whichever file is appropriate.

UPDATE:
Ah, I think I finally understand what you're after.
You don't really want to "eliminate the preprocessor directives" as your original question requested, what you actually want to do is unify the attributes on your methods based on a preprocessor directive.

Yes, that can be done via the magic of a using class alias!
You rename the two attribute classes you're interested in swapping to the same name like this:

#if NUNIT  
using MyAttrib = System.Diagnostics.ConditionalAttribute;  
#else  
using MyAttrib = System.ObsoleteAttribute;  
#endif  

And then you decorate all your methods like this:

[MyAttrib( "attrib arg" )]  
public void TestSomething()  

I've done the exact same thing myself for when a project was going to be unit tested via the Microsoft way but not until we had the version of Visual Studio that supported it.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜