5

I wish to create a custom attribute that suppress a Method from being executed in C# even if it is invoked. For example, In the code block below if the method has 'Skip' Attribute it should not be executed even though it is called from Main.

public class MyClass {

  public static void main()
  {
    aMethod();  
  }

  [Skip]
  public void aMethod() {
    ..
  }

}

How can I achieve this using reflection in C# ?


In the code snippet below I have managed to extract methods that carry the Skip Attribute, I just can't figure out how to stop them from executing!

MethodInfo[] methodInfos = typeof (MyClass).GetMethods();

foreach (var methodInfo in methodInfos)
{
  if (methodInfo.HasAttribute(typeof(SkipAttribute)))
  {
    // What goes here ??
  }
}

Any kinda help or suggestion in the right direction is most welcome :)

shantanusinghal
  • 714
  • 1
  • 8
  • 17
  • 2
    What's the usecase? maybe just do not call the method? or use return; in your if statement? – RAS May 29 '13 at 18:50
  • We can't know what to put in the `if` statement without knowing how to instruct whatever is running your code (self executable? Unit test runner) to not run that method. – vcsjones May 29 '13 at 18:50
  • I want the attribute to **suppress the execution even if the method is called**. – shantanusinghal May 29 '13 at 19:00
  • Who calls the method and under what conditions? Who creates the method and under what conditions? – Wiktor Zychla May 29 '13 at 19:05
  • 1
    OK, so you just want to instrument those methods. You could just say that, spare everybody some why questions :). – Marcel N. May 29 '13 at 19:18
  • See http://stackoverflow.com/a/249071/298754 for some ideas for replacing the body of a method at runtime or post-compile time. – Bobson May 29 '13 at 19:24
  • ConditionalAttribute with a symbol that will never be,compiled? – It'sNotALie. May 29 '13 at 19:33
  • @WiktorZychla anyone could be calling these methods. My intent is that If I have added the attribute on the method definition I should be able to suppress the invocation. – shantanusinghal May 29 '13 at 19:45
  • 1
    If you can add an attribute you can comment out the body. I mean, if you are in control of the source code, you can do just anyhting. – Wiktor Zychla May 29 '13 at 19:56
  • @WiktorZychla I'm also looking after a way to suppress the execution of a method depending on some logic contained within the attribute. An example would be an ASP.NET MVC Action that if called with a querystring flushcache=1, the attribute definition on this method handles the cache flushing logic and prevent the method to be executed as redundant. I think the key point is being able to enable the attribute code to handle the logic that decides whether the method need to skip execution. – Giuseppe Romagnuolo Jan 15 '14 at 16:21
  • There is already [`System.Diagnostics.ConditionalAttribute`](https://msdn.microsoft.com/en-us/library/system.diagnostics.conditionalattribute(v=vs.110).aspx), but it is a compile-time approach. I don't think the thing you ask for exists - For example, if the method's body has already been JITted and inlined into the caller, there is nothing you can do to disable the method as if its code never existed. If you want to insert code between the caller and callee, the insertion has to be in the form as an intermediate object, and that insertion has to happen before the caller is jitted. – rwong Mar 15 '17 at 05:28

2 Answers2

5

It's not clear what you're after.

First off, @Ignore is for telling the JUnit test runner to ignore the test. You didn't mention testing in your question, but we should be clear that that is what @Ignore is for. Test runners in .NET have similar attributes (e.g., in xUnit, the attribute is [Ignore]).

So, if you're using a test runner, find the corresponding attribute for that test runner. If you're not using a test runner, what exactly are you after given that @Ignore is germane only to test running?

Are you writing your own test runner? Why? There are plenty of really good free test runners available. Use them!

I want the attribute to suppress the execution even if the method is called.

Well, that's a code smell if I ever saw one.

You have a few options.

Insert code into every method that you apply [Ignore] to:

[AttributeUsage(AttributeTargets.Method)]
public class Ignore : Attribute { }

[Ignore]
public static void M() {
    var ignoreAttributes =
        MethodBase.GetCurrentMethod().GetCustomAttributes(typeof(Ignore), true);
    if (ignoreAttributes.Any()) {
        return;
    }
    // method execution proceeds
    // do something
}

Or, you can use an interception technique.

Or, you can use a post-compilation framework.

ALL of these have very serious problems. They have problems because what you're doing is a code smell.

jason
  • 236,483
  • 35
  • 423
  • 525
  • I have refined the problem description to better reflect my intent in creating this custom attribute. – shantanusinghal May 29 '13 at 19:01
  • 1
    @ssinghal - You've given us the *what*, but you're still missing the *why*. Tell us **why** you want to do this and we can probably suggest a good way to do it. – Bobson May 29 '13 at 19:26
  • Well the only real purpose of this exercise is to understand reflection and explore it's power. As for your solution of injecting the if(condition)-return block into each method, It gets the job done but I wanted to perform this check externally from one single scope rather that injecting it in my code everywhere. – shantanusinghal May 29 '13 at 19:40
  • @ssinghal - Well, in that case, you've reached the limits of its power. .NET assumes that if you call a function you want that function to execute, and if you don't want it to execute, you don't call it. Reflection will help you call a method you can't explicitly code for, but the way to use reflection to not call a method is to not write any code. – Bobson May 29 '13 at 19:45
  • 1
    @ssinghal - In other words, you've moved beyond trying to use a hammer as a screwdriver and on to trying to use a car as a screwdriver. – Bobson May 29 '13 at 19:46
  • @Bobson nice analogy :D Well is it possible to inject a block of code (the one you proposed) into this method then ? – shantanusinghal May 29 '13 at 19:49
  • No idea. I use a screwdriver on screws, not a car. ;) -- I'd second @wiktor-zychla's suggestion and just comment out the body. Because that's effectively what your attribute would be doing. – Bobson May 29 '13 at 20:33
  • @Bobson, @Jason I'm also looking after a way to suppress the execution of a method depending on some logic in the attribute. Eg. the `OutputCache` does exacly that by preventing the execution of a method depending on whether the result of an Action was previously cached. Similarly I'd like to decorate a Controller Action with an Attribute that intercepts the request, check if the querystring contains a `flushcache=1` param, handles the cache flush logic and prevent the method from executing. Is it a `code smell`? – Giuseppe Romagnuolo Jan 15 '14 at 16:39
  • @GiuseppeR - You should probably ask that as a new question with a link to this one. – Bobson Jan 15 '14 at 18:39
0

Not quite sure what do you exactly want to achieve.
If your intention is to create something behaving like JUnit/NUnit, then here's the code demonstrating how these tools do:

MethodInfo[] methodInfos = typeof (MyClass).GetMethods();

foreach (var methodInfo in methodInfos)
{
  bool ignore = methodInfo.HasAttribute(typeof(SkipAttribute));
  if (ignore)
  {
    // do nothing
  }
  else
  {
     // launch method
     methodInfo.Invoke(/*params here*/);
  }
}

But if you want to make method not be called by CLR even if there is an explicit call - then you need to use Preprocessor Directives.

Community
  • 1
  • 1
alex.b
  • 4,547
  • 1
  • 31
  • 52
  • The above solution will not stop the CLR from invoking the underlying method if an explicit call has been made. – shantanusinghal May 29 '13 at 19:42
  • emm ... what did you mean by `The above solution`? Mine solution or [this one](http://stackoverflow.com/questions/3788605/if-debug-vs-conditionaldebug)? – alex.b May 29 '13 at 20:19
  • BTW, `stop the CLR from invoking the underlying method if an explicit call has been made` - it that what you want to achieve? – alex.b May 29 '13 at 20:20