tags:

views:

196

answers:

2

I have been using the ROWLEX library to handle RDF-s. It is shipped with a designtime GUI tool called OwlGrinder.exe that can generate C# helper classes (.NET assemblies to be exact) from my OWL ontologies. I wonder if anyone knows if I could do the same programatically in runtime.

A: 

Yes, Mr Lame, you can programmatically generate .NET code.

There are a couple options.

  1. Create the code as text.
    You can compile any .cs or .vb source file from within an app. See the help for the Microsoft.CSharp.CSharpCodeProvider class, for a starter. You invoke the compiler programmatically, specifying the resources to embed, where to put the generated assembly, the dependencies, and so on. One scenario here is using a template.cs file, embedding a little more code into it, and then compiling it. The result is an assembly (.dll or .exe or .netmodule if you like) resulting from that code. You can then load that assembly and call into it, using reflection.

  2. Create the code using a document object model.
    The relevant feature area here is called "CodeDom" and it works like the HTML DOM for web pages, except the document object model is used to create .NET code. Programmatically you construct the code, using DOM elements.

example of the CodeDom thing:

var class1 = new System.CodeDom.CodeTypeDeclaration(className);
class1.IsClass=true;
class1.TypeAttributes = System.Reflection.TypeAttributes.Public;
class1.Comments.Add(new System.CodeDom.CodeCommentStatement("This class has been programmatically generated"));
// add a constructor to the class
var ctor= new System.CodeDom.CodeConstructor();
ctor.Attributes = System.CodeDom.MemberAttributes.Public;
ctor.Comments.Add(new System.CodeDom.CodeCommentStatement("the null constructor"));
class1.Members.Add(ctor);

// add one statement to the ctor:  an assignment
// in code it will look like;  _privateField = new Foo(); 
ctor.Statements.Add(new System.CodeDom.CodeAssignStatement(new System.CodeDom.CodeVariableReferenceExpression("_privateField"), new System.CodeDom.CodeObjectCreateExpression(fooType)));


// include a private field into the class
System.CodeDom.CodeMemberField field1;
field1= new System.CodeDom.CodeMemberField();
field1.Attributes = System.CodeDom.MemberAttributes.Private;
field1.Name= "_privateField";
field1.Type=new System.CodeDom.CodeTypeReference(fooType);
class1.Members.Add(field1);

etc etc. You can add regular methods, all sorts of statements in the code, and so on. AFAIK the CodeDom stuff supports everything the language supports. You can do lambdas and linq expressions, conditionals and control flow, anything.

You can then compile that class, and again produce an assembly that you can save to disk or keep in memory and load dynamically.

Cheeso
+4  A: 

ROWLEX just became open source, so now you have the chance to actually look inside the code of OwlGrinder.exe and copy the code from there. However, here is a short example:

 private NC3A.SI.Rowlex.AssemblyGenerator generator;

 private void RunAssemblyGeneration(XmlDocument ontologyFileInRdfXml)
 {
  this.generator = new NC3A.SI.Rowlex.AssemblyGenerator();
  this.generator.GenerateAsync(ontologyFileInRdfXml, "myAssemblyName", 
                                        null, this.OnGenerationFinished);
 }

 private void OnGenerationFinished(string errorMessage)
 {
  if (errorMessage == null)
  {
   // Success
   // Displaying warnings and saving result
   string[] warnings = this.generator.Warnings;
   this.generator.SaveResult(@"C:\myAssemblyName.dll");
                // Important! One generator instance can be executed only once. 
       this.generator = null; 
       this.RejoiceOverSuccess();
      }
  else
  {
       // Failure
       this.MournOverFailure();
      }

    }

If you want to generate assemblies in runtime, I assume that you might want to repeat that over and over again as your user demands. You have to watch out here, because .NET does not allow you to unload an assembly. Therefore you cannot get rid of the assemblies from your previous runs. The solution is that you execute the generation code every time in a new AppDomain which can be unloaded. OwlGrinder.exe does exactly this, you might want to peak inside the MainForm.cs

ROWLEX Admin