In other words, is there an Attribute that marks a segment of code as not too old, but too new and therefore not quite ready for widespread use?
If I'd have to create a custom Attribute to accomplish this, that's fine. I just wanted to make sure first.
No, there's nothing standardized around this. You might want to consider just not exposing code like that though - or only exposing it in beta builds etc.
Not an attribute, but there are preprocessor directives (https://msdn.microsoft.com/en-us/library/ed8yd1ha.aspx) which we can use to mark a region of code as "too new" to run. Basically you can define a flag to indicate that piece of code is ready.
Here is an example:
#define FOREST_CAN_RUN
//undef FOREST_CAN_RUN --> disable that feature
using System;
namespace Test
{
public class Forest
{
public void Run()
{
#if FOREST_CAN_RUN
Console.Write("Run Forest, Run !");
#else
Console.Write("Sorry, Jenny");
#endif
}
}
public class Program
{
static void Main(string[] args)
{
Forest f= new Forest ();
f.Run();
}
}
}
Related
the C# harmony documentation: https://github.com/pardeike/Harmony/wiki/Prioritiy-annotations
my question is that not able to run the C# harmony example successfully
the postfix annotation didn't get injection log printed as expected after Class and method get patched that i didn't see "injection logs" get printed.
c# code example below. Can someone help me find the issue
you may paste into https://dotnetfiddle.net/ to debug it.
using System;
using System.Collections.Generic;
using System.Reflection;
using Harmony;
public class Program
{
public static void Main()
{
var harmony = HarmonyInstance.Create("net.example.plugin");
harmony.PatchAll(Assembly.GetExecutingAssembly());
Program p = new Program();
p.Bar();
}
[HarmonyPostfix]
[HarmonyPatch(typeof(Program), "Bar")]
public static void Postfix_Bar(){
Console.WriteLine("postfix Bar log"); // this never gets printed as expected.
}
[HarmonyPostfix]
[HarmonyPatch(typeof(Program), "Foo")]
public static void Postfix_Foo(ref string res){ //however, this gets error res could not be found. https://github.com/pardeike/Harmony/wiki/Prioritiy-annotations
Console.WriteLine("postfix Foo log");
res = "new value";
}
public void Bar() {
Console.WriteLine("Hello World !!! ");
}
static string Foo()
{
return "secret";
}
}
The main problem is that PatchAll() looks for classes that have at least on [HarmonyPatch] annotation. Your patches are in the class Program which does not have that annotations. This is the main problem in your example.
Solution: either annotate your Program class like this:
[HarmonyPatch]
public class Program
{
}
or create a new class that has that annotation.
The second problem I can see is that Postfix_Foo(ref string res) uses res which does not follow the documented standard for naming patch arguments. It can either be the name of an argument that the original method has (it has no arguments) or refer to the result, which requires it to be named __result.
The comment about priority annotations is misplaced too because they only apply to multiple patches to the same original method.
Finally, you call Bar() after patching which means that Foo is never called - not sure if that’s intended.
This question already has answers here:
How to stop evaluation of parameters in calls to debug functions when in Release build (C#)
(3 answers)
Closed 4 years ago.
Please note that I am aware of Debug.Print - the Console.WriteLine is a very simplified example of what I'm trying to do.
Is there a way to have a single line of code which exists only in Debug mode, which does not appear in Release at all?
I have some commands which help me debug the execution of a performance-critical section of code, and I have placed a large number of them all over the function in key places.
Here is an example of what I've done:
using System;
public class C {
public Object _obj = new object();
public void M()
{
Alpha("This goes away in Release");
Alpha(_obj.GetHashCode() + "...but this doesn't");
#if DEBUG
//But I don't want this three line deal.
Alpha(_obj.GetHashCode() + "...of course this does get removed");
#endif
}
public static void Alpha(String s)
{
#if DEBUG
Console.WriteLine(s);
#endif
}
}
The issue is that in release mode, the compiler recognizes that the first call does nothing in release mode, and removes it. But it does not do that in the second call. I know this because I have tested it in SharpLab: https://sharplab.io/#v2:EYLgHgbALANALiAhgZwLYB8CQBXZBLAOwHMACAZQE9k4BTVAbgFgAoTAB22ABs8BjE3lxTISAYRIBvFpnace/APLAAVjV5wSAfQD2KkgF4SBGgHcSu1eoAUASiatZ3PiQBu2vABMSAWVslpmFIOmACCXGwAFohWAEQAKhF4IkTaNCKIJogUJIQkAEo0XDQoNDF2AaHhUVY6KgB0AOI0cAASKBGi2h40fgDUJDF1Q8DYGnCJIh6pyAQAAgC0AIxwZfYymBUAxHgAZiQAIgCiAEIAqg3+wZgA9NfHoyQAkiRTc0samQRjEyTjAE40GgkHjGF7FLh1CqVSLRWrKRrNNrIDpdHo2Ej9QZDbR7XjabB/ZBA8ZJF7TEhEZokAGobQuGgeVZbGgEDy7KEBAC+AQCHCc/GoiDgzjcnhIYRhVjIcD+hFIyBsASC622eyOZwaUM6BGQ2iKdQA6rLaAAZQg9BVrGSbFlsnZc6ScoA==
Is there any way of avoiding the three-line version?
Yes, just put a [Conditional(...)] attribute on the method that you need to "not exist" unless you are using the Debug configuration:
[System.Diagnostics.Conditional("DEBUG")]
public static void Alpha(String s)
{
Console.WriteLine(s);
}
All calls to such methods are effectively removed (not compiled) unless the specified symbol is present.
Note that a restriction applies: [Conditional(...)] can only be used for void methods.
You probably desire ConditionalAttribute:
using System;
using System.Diagnostics;
public class C {
public Object _obj = new object();
public void M()
{
Alpha("This goes away in Release");
Alpha(_obj.GetHashCode() + "...this is ommited");
}
[Conditional("DEBUG")]
public static void Alpha(String s)
{
Console.WriteLine(s);
}
}
See SharpLab for results.
A neat trick you could use for void methods is the ConditionalAttribute, used like this:
[Conditional("DEBUG")]
public static void Alpha(String s)
{
/***/
}
The compiler would remove all calls to those methods if the symbol is not defined.
Also there's this monstrosity:
if (System.Diagnostics.Debugger.IsAttached) /* your debug */
Works in one line, but requires an attached debugger and also is not "removing" the code.
Okay, so working on learning some C#. Great language, love working with it in general, but I'm not understanding how to get over this lack of utility classes. In essence, I want to set up a general utilities class that can be contained in a folder and used for any project simply by doing a "using namespace Globals/Utilities/etc." command. In essence:
using System;
namespace Globals {
public static class Commands {
public static void WaitForReturn() {
Console.WriteLine("Press Enter to continue.");
Console.ReadLine();
}
}
}
Similar to the above, such that in any other class I can call the functions by including it as a preprocessing directive.
using System;
using Globals;
namespace RectangleDemo {
<rectangle definition here>
class Demo {
static void Main(string[] args) {
Rectangle r = new Rectangle();
Rectangle s = new Rectangle(5, 6);
r.Display();
s.Display();
WaitForReturn();
}
}
}
As it is, I'm trying to simply compile my 'utility' class (with more than what is listed above) to check for errors, but it's just telling me that it can't compile it because there's no main method. Any suggestions?
(Yes I'm aware I have a java coding style, I'm okay with that!)
With C#6 you can import static methods so you can end up with the following coding style:
using System;
using static Globals.Commands;
namespace MyConsole
{
internal class Program
{
private static void Main(string[] args)
{
WaitForReturn();
}
}
}
namespace Globals
{
public static class Commands
{
public static void WaitForReturn()
{
Console.WriteLine("Press Enter to continue.");
Console.ReadLine();
}
}
}
And as suggested by Tim, if you don't want a main entry point, use a Class Library project instead of a Console Application.
C# doesn't work the way you're expecting. There is no relationship between importing namespaces/classes and files so doing using Globals; does not translate to file content inclusion à la C/C++ (i.e. not the same as #include "Globals.cs").
On the command line, the C# compiler accepts the list of files that make up your sources:
csc Demo.cs Globals.cs
If you are using an IDE like Visual Studio, you would link the Globals.cs into your project. And by link, I mean more like a symbolic link (though it is not in actual fact) than static linking via a linker as you would have typically in a C/C++ setup.
So to make your scenario of “inclusion of common code” work, you need to compile by simply always adding Globals.cs to the list of C# files making up your project (supplied to the compiler on the command line or added to your project in IDE) and then using a static import:
using System;
using static Globals.Commands; // <-- import statically allows methods to be
// used without class name qualification
namespace RectangleDemo {
// <rectangle definition here>
class Demo {
static void Main(string[] args) {
Rectangle r = new Rectangle();
Rectangle s = new Rectangle(5, 6);
r.Display();
s.Display();
WaitForReturn();
}
}
}
Is it possible to skip all tests from a specific class like in NUnit
[TestFixture]
[Ignore("Reason")]
public class TestClass {
}
No - there is no such facility at present, and the last time it was requested it was considered too low value to add,
One quick way of achieving the effect in xUnit is to comment out the public - private classes are not reflected over (obviously it won't appear on the skip list that way though).
UPDATE: Another way is to put a TraitAttribute on the class and then (assuming you're using the xunit.console runner) filter it out by running with /-trait traitName. (e.g. you can achieve ExplicitAttribute, some aspects of the BDD frameworky technique of Pending tests and similar semantics that way - of course the big problem is they don't show up in any reports when using any of these filtering techniques)
UPDATE 2: You can do
const string skip = "Class X disabled";
[Fact(Skip=skip)]
void Test() {}
Then you can change to to const string skip = null to undo the skip. The (dis)advantage of this is that the test is still shown as a Skipped test in the test list, generally with a reason included in the test run report (vs making it private which makes it likely to be forgotten)
Here is my hack to avoid error xUnit1000: Test classes must be public (checked on single Fact, I think Theories can be hacked this way, too).
// Uncomment to enable tests
//public class FactSwitch : FactAttribute { } // public! ahh, a bug!
// Uncomment to disable tests
internal class FactSwitch : Attribute { }
public class MyTests
{
[FactSwitch]
public void MyTest1()
{
"it".ShouldBe("it");
}
}
(3 years later)
While searching for the same solution I found there are better ways to do the same.
Let's rewrite the example above in a way Ruben Bartelink suggested (continuation of his idea).
public class MyTests
{
//const string SkipOrNot = null; // Run all tests
const string SkipOrNot = "reason"; // Skip all tests
[Fact(Skip = SkipOrNot)]
public void MyTest1()
{
"it".ShouldBe("it");
}
}
Nathan Cooper suggested a good improvement for my idea:
public class MyTests
{
// Uncomment to disable tests
//private class FactAttribute : Attribute { }
[Fact]
public void MyTest1()
{
"it".ShouldBe("it");
}
}
So I like both ideas from Ruben and Nathan. There is a subtle difference between using Skip="something" (Ruben) and not using Skip at all. Using "Skip" will put all your tests in a "Skipped tests" warning zone, while "FactAttribute : Attribute" will hide them.
I've found yet another way of temporary disabling entire class without compiler warning.
Disabled:
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "xUnit1000:Test classes must be public", Justification = "Disabled")]//*/
/*
public /**/class DatabaseTests
{
}
to enable move the /* one line up (i.e. using alt+up):
/*
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "xUnit1000:Test classes must be public", Justification = "Disabled")]//*/
public /**/class DatabaseTests
{
}
Note that using full namespace path for SupressMessage does not mess up with your usings.
You need to set the your class access level as as internal and surpress message as #Miq did:
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "xUnit1000:Test classes must be public", Justification = "Disabled")]
internal class MyClassThatIsNotATestClass
{ ... }
You can create LocalOnlyFactAttribute
public class LocalOnlyFactAttribute : FactAttribute
{
//uncomment to run on local
//const string skip = null;
//keep this to avoid slow running tests on other env
const string skip = "Disabled slow running tests.";
public override string Skip { get => skip; set => base.Skip = value; }
}
As far as I know, the simplest way to dynamically skip a whole xUnit test class at runtime is to use the TestFrameworkAttribute at the assembly level, to point to a class that implements the ITestFramework interface (or inherits from XunitTestFramework, which is simpler) and which overrides the CreateDiscoverer() method to return another class, that implements the ITestFrameworkDiscoverer interface (or inherits from XunitTestFrameworkDiscoverer, which is simpler), where you can finally override the IsValidTestClass() method, to decide whether a class should be skipped or not.
Here is some sample code:
[assembly: TestFramework("MyNamespace.Xunit.MyTestFramework", "MyAssembly")]
namespace MyNamespace.Xunit
{
public class MyTestFramework : XunitTestFramework
{
public MyTestFramework(IMessageSink messageSink)
: base(messageSink)
{
}
protected override ITestFrameworkDiscoverer CreateDiscoverer(
IAssemblyInfo assemblyInfo)
=> new MyTestFrameworkDiscoverer(
assemblyInfo,
SourceInformationProvider,
DiagnosticMessageSink);
}
public class MyTestFrameworkDiscoverer : XunitTestFrameworkDiscoverer
{
public MyTestFrameworkDiscoverer(
IAssemblyInfo assemblyInfo,
ISourceInformationProvider sourceProvider,
IMessageSink diagnosticMessageSink,
IXunitTestCollectionFactory collectionFactory = null)
: base(
assemblyInfo,
sourceProvider,
diagnosticMessageSink,
collectionFactory)
{
}
protected override bool IsValidTestClass(ITypeInfo type)
=> base.IsValidTestClass(type) &&
FilterType(type);
protected virtual bool FilterType(ITypeInfo type)
{
// Insert your custom filter conditions here.
return true;
}
}
}
Tested with xUnit 2.4.1.
We are using it in Pomelo.EntityFrameworkCore.MySql (see AssemblyInfo.cs and MySqlXunitTestFrameworkDiscoverer.cs) (a bit more complex than the sample code here).
You could achieve this through a custom ITestClassCommand.
See http://mariangemarcano.blogspot.be/2010/12/xunitnet-running-tests-testcategory.html
Here's another hack that requires minimal changes to code
using FactAttribute = System.Runtime.CompilerServices.CompilerGeneratedAttribute;
using TheoryAttribute = System.Runtime.CompilerServices.CompilerGeneratedAttribute;
Any compatible attribute can be used for the replacement.
If you also use the InlineDataAttribute then you'll need to define a replacement as I don't think there's an existing compatible attribute.
using InlineDataAttribute = DummyDataAttribute;
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
internal class DummyDataAttribute : Attribute
{
public DummyDataAttribute(params object[] data)
{
}
}
Adding a reason almost after one year after the initial question. I have a set of tests which are calling real server apis, and I would like to run then on demand. With nUnit, it has Ignore attribute : with that set, test runner will skip those tests, but I can still manually run it.
xUnit has no such feature. The nearest one is setting such a class level attribute, and comment it out when I want to run it.
Consider creating LocalOnlyFactAttribute, which can be reused across multiple test files.
public class LocalOnlyFactAttribute : FactAttribute
{
//uncomment to run on local
//const string skip = null;
//keep this to avoid slow running tests on other env
const string skip = "Disabled slow running tests.";
public override string Skip { get => skip; set => this.Skip = value; }
}
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
Moled = 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.