C#: writing MSIL to add a preprocessor directive?

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.

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.

Excellent answer, and the route that I'm going to end up following. I don't know if I should choose you as the selected answer to this question because it doesn't directly answer my MSIL question, but you're addressing the problem behind several of my recent questions! – Sarah Vessels Jan 30 '10 at 21:00 2 Are you saying he should use regular expressions instead?

;) – Remus Rusanu Jan 30 '10 at 21:44 @Remus - sounds like you know the quote. Sarah is probably a s/he. No, regex is not indicated here.

– Hans Passant Jan 30 '10 at 21:48.

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.

In short, no. Pre-processing directives have no IL representation, since they only exist as metadata used during compilation of a source file. The kind of thing you're doing might be better as a custom FxCop rule.

It has interesting ways in which you can hook up into the compiler pipeline. One such feature is called syntactic attributes, which are attributes that implement an interface that the compiler calls, so that they can participate in code generation. Class Person: getter(FirstName) _fname as string getter(LastName) _lname as string def constructor(required fname, required lname): _fname = fname _lname = lname The attributes in this code will generate public getters for the fields and null checks for the constructor parameters.

It will all end up in the compiled assembly. I've always wanted this kind of extensibility to be part of the C# compiler. Maybe it will one day.

Until then, you can use a post-compiler, like CciSharp. CCiSharp will rewrite the CIL based on special attributes in the assembly, just like with Boo synctatic attributes. Given this code: class Foo { Lazy public int Value { get { return Environment.

Ticks; } } } CCiSharp will mutate the code based on the LazyAttribute to this: class Foo { int Value$Value; // compiler generated int Value$Initialized; int GetValueUncached() { return Environment. Ticks; } public int Value { get { if(!this. Value$Initialized) { this.

Value$Value = this. GetValueUncached(); this. Value$Initialized = true; } return this.

Value$Value; } } CCiSharp is based on the Common Compiler Infrastructure project, the same used to implement the code contracts post compiler in the upcoming . NET Framework 4.0.So this is how you can mutate the generated CIL. But, a #warning directive does not have a CIL representation, it's a compiler directive only.

To add this directive, what you must mutate is not the generated CIL, but the C# code itself. You'd have to implement a C# parser for that. I think the best option is, as stated in other responses, to create a post-build event that will reflect over the generated assembly and issue the desired warning.

You could probably do this with a post-build task that reflects your compiled code and checks for the condition. I don't have any experience creating MSBuild tasks but it's a place you can start. Another suggestion once .

NET 4.0 is released is to use Code Contracts to specify requirements for the parameters of the attribute's constructor. This would be caught at compile time.

My gut feeling is no you cannot inject a #warning directive based on a custom attribute and condition since that is caught at compile time by the compiler, it is like a chicken and the egg situation as the custom attribute would have to be evaluated first before injecting a #warning but in order for that to happen a compile time action must be carried out first. Hope this helps, Best regards, Tom.

I suspect the answer would be no, you can't, because the #warning directive is a CSC thing (i.e. You are directing the compiler to act in a certain fashion). When writing raw MISL, obviously, CSC doesn't come into mix, therefore there is no compiler to direct to do something.

Basically the a directive (indicate like '#warning' is an instruction to CSC to behave in a certain way under specified conditions.

I cant really gove you an answer,but what I can give you is a way to a solution, that is you have to find the anglde that you relate to or peaks your interest. A good paper is one that people get drawn into because it reaches them ln some way.As for me WW11 to me, I think of the holocaust and the effect it had on the survivors, their families and those who stood by and did nothing until it was too late.

Related Questions