Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C#: writing MSIL to add a preprocessor directive

Is it possible in C# to write MSIL code that will add a preprocessor directive to the code, e.g., #warning, if a certain condition is met? Or maybe this can be done with reflection, I don't know.

I'm trying to write a custom attribute that, if applied incorrectly to a class's method or property, will generate a compiler warning. Using the existing Obsolete attribute won't work because then just using my custom attribute causes the warning, and I don't want that. I want the custom attribute constructor to check for a condition, and if that condition is true then cause a compilation warning.

Update: after reading back over my question, I think what I'm asking for is impossible just because I'm mixing compile-time and runtime constraints. I think I'll end up going with a post-build task to check the just-built DLL and have it spit out error messages if the condition is true.

like image 885
Sarah Vessels Avatar asked Jan 30 '10 19:01

Sarah Vessels


2 Answers

I saw this question coming from your previous thread. To mis-quote the great Jamie Zawinski: "Some people, when confronted with a problem, think "I know, I'll use an attribute." Now they have two problems".

An attribute is merely out-of-band data, compiled into an assembly's metadata. It cannot affect program execution or tool behavior, unless the program or the tool is explicitly programmed to recognize the specific attribute. It needs to do so using Reflection.

What you need to do is write your own tool. It should execute after an assembly is built, using the Post-Build step for a project. It needs to load the assembly and use Reflection to iterate the types in the assembly. For each type, iterate the methods with Type.GetMethods() and use MethodInfo.GetCustomAttributes() to discover and construct an attribute that might have been programmed.

You can use Type.GetInterfaces() to discover which interfaces are implemented by the type. You can now complain when you see that a method is present that implements an interface method but is missing an attribute that says so. And your ultimate goal: you can complain when you see a method with an attribute that says it implements an interface method but the type no longer inherits it.

Use Environment.ExitCode to make the tool fail the build if you see anything objectionable. This takes care of enforcement. Btw: programmers really hate to break the build. That might well encourage them to use the attribute religiously. Or it might encourage them to edit the post build step.

like image 167
Hans Passant Avatar answered Oct 28 '22 02:10

Hans Passant


The compiler stores two things for custom attributes:

  • The attribute constructor to call
  • The data for each parameter to pass to the constructor

The constructor is only called when the application is running and someone calls GetCustomAttributes for your Assembyl, Type, MethodInfo, ParameterInfo, etc.

You have some other options to consider:

  • Write a custom MSBuild task that runs after the compilation stage, loads the compiled assembly and checks the application's attribute usage.
  • Use the AttributeUsage attribute to specify the code items to which the attribute can be applied.
  • Defer the attribute validation to runtime.
like image 41
Sam Harwell Avatar answered Oct 28 '22 02:10

Sam Harwell