简体   繁体   中英

How to automatically create (e.g.) singleton with c# using CodeDOM / T4 / PostSharp / whatever?

I'm looking for a way to automatically generate (eg) singleton , like:

[SingletonPatternAttribute]
public class Logger {
    public void Log (string txt) { /* do logging... */ }
}

as an attempt to eliminate boilerplate.

Does somebody know how it can be accomplished ? I know there are CodeDOM , Reflection.Emit , T4 and so on. Also - there is (most notably) PostSharp , but I'd be really glad to see a real solution for the above challenge.

I can do the code-generation in the constructor, for instance, but compilation-time is obviously much better.

Edit:

The issue here is not the Singleton , but the generative / meta programming in C# - how to create code / eliminate boiler-plate in the best way - what kind of concrete examples there are ?

I do this exact thing for my logging class, using an IOC container and adding the scope when mapping/binding the object. For instance using Ninject, the binding would be:

Bind<ILogger>().To<Logger>().InSingletonScope();

Then in my classes where I want to use my singleton logger, I can use property injection:

[Inject]
public ILogger Logger { get; set; }

Some time passed, but I have not read a satisfactory response, so I will write up what I have done in the past. I am still very interested in other approaches as well, as I feel that what I have achieved is not ideal and I myself would like to do better.

I have tried, in the past years, three of the four listed approaches for code generation of "enriched" classes:

  • Reflection.Emit
  • T4
  • CodeDom (but I discarded this early, as it was at the time of my project, not complete!)

plus other three:

  • IL rewriting using the Profiler API Here and here (actually used)
  • Interception using ContextBoundObject Here (only tested)
  • Embedding a C# compiler (Roslyn/MonoCSharp) Here and now also scriptcs (only researched, not atually used)

In general, I investigated all these tools to obtain some "weaving" of code, in an AOP way, starting from a something similar to the OP example: make classes and methods tagged with attributes "special", modifying their behaviour. At the time of my first project, AOP solutions for C# were not mature enough (but this may have changed meanwhile), so I cannot say anything about PostSharp, for example. My purpose was, as I said, quite similar: based on attributes on classes and methods, add some additional code (and class members as well) to the classes. I ended using Reflection.Emit for the prototype, and IL rewriting using the Profiler API for the final thing.

The second project, for which I ended up using T4, was slightly different; it already used a code generator (more specifically, a parser generator), but we needed further (automatic!) modification of the generated source code.

Reflection.Emit

I used the following approach: a class (let's call it MakeProxy) walked a given assembly, searching for attributes, and then emitted a new dll (a "proxy") which called the original assembly under the hood, providing the desired interface and behaviour to the user.

I actually used the class in a tool, a .NET executable, which was run by MS Build after the compilation pass.

The main disadvantage: references can be difficult to handle. You need to reference the automatically generated dlls, so you have to split your code in different projects, and you cannot even reference the original project(s) in a solution... it may be not acceptable. Also, you "see" (in the IDE) the original code too, and not the generated code; this may make debugging difficult.

Profiler API

In this case, you do the same work as for Reflection.Emit, but you do not need to pre-build any "proxy"; code is injected at IL generation time (ie once, which is quite good performance-wise). You just write your (unmanaged) profiler DLL, and start your program under it. Your "profiler" will get notified of which functions are executed (or, better, which functions are JITed) and you can act accordingly.

The main disadvantages: you cannot modify the "structure" (methods, fields,...) of your classes (not easily); IL generation with unmanaged API is quite difficult (you have to take care of many things, and debugging when something goes wrong is a real nightmare!) The main advantages: no modification is required to the original code (especially, no modification is required on the caller side - this is what lead me towards this solution in the end, given the requirements of that particular project).

T4

I used T4 for a different project, but I can share my findings here. It is good for transforming text, but not really for transforming code: syntax becomes "weird" (you have code, and code inside the code to produce code... you get lost easily).

Main advantage: it is well integrated with the IDE and with the build system; you get intellisense support; it is easy to start with; you actually see what you are debugging

Personally, I would like to have (or build myself) something like T4, but that performs C# -> C# code transformation; in that way, you could have the advantages of the IDE (including intellisense on both the "original" and the "produced" thing) and the power of Reflection.Emit. You probably need to build both the C#/C# compiler, and a VS plugin to get all these goodies though.

One final note: today, I would use something more "advanced" than Reflection.Emit, like IKVM emit, or Sigil

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM