views:

80

answers:

2

This is a problem I've been struggling to solve for a while. I need a way to either replace code in the method with a parsed code from the template at compile time (PostSharp comes to mind) or to create a dynamic proxy (Linfu or Castle). So given a source code like this

[Template]

private string GetSomething()

{

var template = [%=Customer.Name%]

}

I need it to be compiled into this

private string GetSomething()

{

MemoryStream mStream = new MemoryStream();

            StreamWriter writer = new StreamWriter(mStream,System.Text.Encoding.UTF8);

writer.Write(@"" );

writer.Write(Customer.Name);

StreamReader sr = new StreamReader(mStream); 

writer.Flush();

mStream.Position = 0; 

return sr.ReadToEnd();

}

It is not important what technology is used. I tried with PostSharp's ImplementMethodAspect but got nowhere (due to lack of experience with it). I also looked into Linfu framework. Can somebody suggest some other approach or way to do this, I would really appreciate. My whole project depends on this.

Assumptions:

  1. Code can appear in any class.
  2. Template code will always be annotated with attribute [Template]
  3. Template method will always return string.

Parsing of the code from one form to another is already done. Now I just need a way to replace it.

"Beefer" example:

  [Test]
        public void can_parse_csharp_code_template3()
        {
            var template = @"<template> [%= GetUsing() %]
    namespace [%= GetModelNamespaceName(.metaPackage) %]
    {
    [%= .visibility.ToString().ToLower() %] class [%= .Name %] : INotifyPropertyChanged [%= If(.IsPersistent, "", PersistenObject"", """") %]
        {
            #region Constructors
            [%= ConstructorTemplate.Create(metaObject).GetParameterlessConstructorCode %]
            #endregion

            #region Attributes

            [%= From attribute In metaObject.attributes _
                Select (AttributeTemplate.Create(attribute).GetSourceCode) %]
            #endregion

            #region Relationships
            [%= From relationship As Relationship In metaObject.relationships _
                Select (RelationshipTemplateFactory.CreateFor(relationship).GetSourceCode()) %]
            #endregion

            #region Methods
            [%= From operation In metaObject.operations _
                Select (MethodTemplate.Create(operation).GetSourceCode) %]
            #endregion

            #region ""INotifyPropertyChanged""
            [%= GetOnPropertyChanged() %]
            #endregion
            }
        }</template>";

            Console.WriteLine(TemplateParser.GetParsedResult(template));

        }
+1  A: 

Have a look at T4 (Text Template Transformation Toolkit).

<#@ template language="C#v3.5" #>
<#@ assembly name="System.Core" #>
<#@ output extension=".cs" encoding="utf-8" #>

private string GetSomething()
{
    <# Generate("Customer.Name"); #>
}

<#+
private void Generate(string s)
{
    WriteLine(@"MemoryStream mStream = new MemoryStream();");
    // ...
}
#>
dtb
@dtb: T4 teplates can appear anywhere in the body of any class?
epitka
@epitka: Yes. You create a `.tt` file which contains your C# code amended with `<#= ... #>` and/or `<# ... #>` directives. The `.tt` is then transformed to a `.cs` file by the *TextTemplatingFileGenerator* custom tool before compilation.
dtb
@dtb: So VS will generate the file and then compile it and I only need to deploy .dll?
epitka
@epitka: Yes. Visual Studio will run the custom tool for you. The result is an assembly as if you had written the generated C# file by hand.
dtb
A: 

A tool that can parse C#, pick out attributes, and transform that code any way you'd like, is the DMS Software Reengineering Toolkit and its C# Front End.

DMS parses your files, builds full abstact syntax trees, and allows you to write custom transformations that can expand a point in the text (what most code generators like T4 do) or more importantly replace any construct (both local and/or distributed across the set of files that make up the application) with any other code you might like to generate.

You appear to have some idea about the metalanguage for producing code fragments, e.g.,

  From operation In metaObject.operations _ 
            Select (MethodTemplate.Create(operation).GetSourceCode) 

That metalanguage AFAIK isn't C#. With DMS, you can define a parser for the metalanguage, and process the meta langauge into trees as the code generator encounters the constructs. With a small interpreter over such trees, you can convert metalnguage text into generator actions producing the text of interest.

[I'm the CTO behind DMS].

Ira Baxter
Thank you for taking time to answer the quiestion. I will certainly look into you tool. You are right, it is not c# reflection meta data, but custom meta model that targets model driven development.
epitka