Archives

Next Archive Previous Archive

01 Sep - 30 Sep 2003
01 Oct - 31 Oct 2003
01 Nov - 30 Nov 2003
01 Jan - 31 Jan 2004
01 Feb - 28 Feb 2004
01 Mar - 31 Mar 2004
01 May - 31 May 2004
01 June - 30 June 2004
01 Jul - 31 Jul 2004
01 Nov - 30 Nov 2004
01 Jan - 31 Jan 2005
01 Apr - 30 Apr 2005
01 May - 31 May 2005
01 Jul - 31 Jul 2005
01 Aug - 31 Aug 2005
01 Sep - 30 Sep 2005
01 Oct - 31 Oct 2005
01 Nov - 30 Nov 2005
01 Dec - 31 Dec 2005
01 Jan - 31 Jan 2006
01 Feb - 28 Feb 2006
01 Mar - 31 Mar 2006
01 May - 31 May 2006
01 June - 30 June 2006
01 Aug - 31 Aug 2006
01 Sep - 30 Sep 2006
01 Nov - 30 Nov 2006

Last Comments

buy vicodin1750 (Another TreeView): jekcrcSorry for that.
generic nexium892… (Back from holiday…): fmefccSorry for that.
buy valium2307 (So many news in M…): hmjwtlSorry for that.
order ambien6966 (Summer is approac…): lghptpSorry for that.
buy fioricet1110 (Namibia): tkksjrSorry for that.
online lexapro321… (Using TreeView cu…): bpwmbjSorry for that.
buy lipitor9884 (NUnit add for Mon…): kwgronSorry for that.
online soma7121 (Glade 3 in MonoDe…): ghepodSorry for that.
buy vicodin8303 (An exciting GUADE…): tmtnroSorry for that.
generic fioricet3… (Visiting Mexico): iinhfdSorry for that.

Last Referrers

12:03 mp3s.good.one.pl/download-mp3-…
12:01 mp3clank.com/viewtopic.php
12:00 musicforum.org.ua/viewtopic.ph…
11:58 mp3s.good.one.pl/download-mp3-…
11:57 buyhghsupplement.info/2008/01/…
11:56 livemarket.com.ua
11:54 playsexmovies.com
11:54 mp3s.good.one.pl/download-mp3-…
11:52 prisonbreakthat.com/movie/8-Th…
11:52 health-db.com/forum/login.php

Links

Google
Pivot

To change this list, edit the file '_aux_link_list.html' in your pivot's templates folder.

Stuff

Powered byPivot - 1.24.3: 'Arcee' 
XML Feed (RSS 1.0) 

About

This is the default template for Pivot. You can change this text by editing the file templates/frontpage_template.html in your pivot folder.

Linkdump

+ 3 - 5 | § Another TreeView

I'm also working on a TreeView, and mine already has checkboxes...

+ 5 - 5 | § A new code generation API

I find System.Reflection.Emit too low level for some kind of uses. If you are writing a compiler, SRE is just perfect, since you need to have full control of the IL being generated. However, if you are writing, guess what, an xml serializer, SRE is not so useful. An xml serializer needs to generate code for writing and reading the contents of an object, and this code is not simple (it will include type conversions, method calls, loops, etc.). For complex types the IL code may be very long, and debugging this code if something goes wrong would be really hard.

The existing XmlSerializer does not generate IL, instead it generates C# code and compiles it using the C# compiler. This solution has several problems: the generation of the serializer is slow and the generated code is limited to what C# can do (for example the serializer can't access private fields).

That's why I've been thinking on an new kind of IL generation API. With this API you can generate methods and classes using high level expressions, that will later generate the IL. It's a kind of on-the-fly compiler. You have the benefits of SRE (the generation of the code is very fast, and it is not limited to the features of any language), and the benefits of using a rather high level language.

Here is a example. This code generates a class with a static method that adds two numbers and returns the result:
CodeClass cls = CodeModule.Shared.CreateClass ("TestClass"); CodeMethod method = cls.CreateStaticMethod ("AddNumbers", typeof(int), typeof(int), typeof(int)); CodeBuilder cb = method.CodeBuilder; cb.Return (method.GetArg (0) + method.GetArg (1)); cls.CreateType (); object res = method.MethodInfo.Invoke (null, new object[] {2,3}); Console.WriteLine ("Result: " + res); Console.WriteLine (cls.PrintCode ());I think the code is easy to understand by itself. The first two lines create the class and the static method. CodeModule, CodeClass and CodeMethod wrap ModuleBuilder, TypeBuilder and MethodBuilder respectively, and add some high level methods to make things easier. CodeBuilder can be used to generate the code of the method. In this example, the only statement needed is a return statement, which returns the addition of the method arguments.

What is interesting is how the addition is generated. "method.GetArg (n)" returns an object of type CodeExpression that represents the n-th argument of the method. The operator + for CodeExpression is overloaded, and returns a CodeAdd expression object that generates the addition of both expressions (other binary operators are also overloaded).

The call to CodeClass.CreateType() generates the IL for the method and creates the type. What is also interesting is the method CodeClass.PrintCode(). This method returns a C# representation of the generated IL. This is not fully compilable C#, its goal is only to give an overview of the code that has been generated and make easy to verify that it is generating what it is supposed to generate. It will show something like this:
public class TestClass { static System.Int32 AddNumbers (System.Int32 arg0, System.Int32 arg1) { return arg0 + arg1; } TestClass () { } } Now let's see a more complex example. This example generates a method that calculates the Fibonacci serie up to a number entered by the user:
CodeClass cls = CodeModule.Shared.CreateClass ("TestClass"); CodeMethod method = cls.CreateStaticMethod ("Run", typeof(void)); CodeBuilder cb = method.CodeBuilder; CodeValueReference max = cb.DeclareVariable (typeof(int)); CodeValueReference v1 = cb.DeclareVariable (typeof(int), Exp.Literal (0)); CodeValueReference v2 = cb.DeclareVariable (typeof(int), Exp.Literal (1)); CodeValueReference sum = cb.DeclareVariable (typeof(int)); cb.ConsoleWriteLine (Exp.Literal ("Enter a number:"), max); CodeExpression txt = Exp.Call (typeof(Console), "ReadLine"); cb.Assign (max, Exp.Call (typeof(int), "Parse", txt)); cb.ConsoleWriteLine (Exp.Literal ("Generating Fibonacci numbers until {0}"), max); cb.While (v2 < max); cb.Assign (sum, v1 + v2); cb.Assign (v1, v2); cb.Assign (v2, sum); cb.ConsoleWriteLine (v2.CallToString()); cb.EndWhile (); cb.ConsoleWriteLine ("Done"); cls.CreateType (); Console.WriteLine (cls.PrintCode ()); method.MethodInfo.Invoke (null, null); In this example CodeBuilder is used to declare variables, to start and end a While loop, to assign values and so on. If CodeBuilder is the class to use to generate statements, the Exp class is the starting point for generating expressions. It can be used to generate literal values, object creation, etc.

It is also interesting to note that all expression types are checked by the generator, and it will throw an exception if you try, for example, to assign an expression to a variable that has not been declared with the same type, or if you are calling a method with incorrect parameters.

The last example: a very simple serializer generator. The method GenerateSerializer takes a type as parameter and returns an object of type ISerializer that can be used to serialize objects of that type.
using System; using System.Reflection; using Mono.CodeGeneration; using System.Xml; public class Test { public interface ISerializer { void WriteObject (XmlWriter writer, object obj); } public static void Main () { ISerializer ser = GenerateSerializer (typeof(Data)); XmlWriter writer = new XmlTextWriter (Console.Out); ser.WriteObject (writer, new Data ()); } public static ISerializer GenerateSerializer (Type targetType) { CodeClass cls = CodeModule.Shared.CreateClass ("SerializerFor" + targetType.Name, typeof(object), typeof(ISerializer)); CodeMethod method = cls.ImplementMethod (typeof(ISerializer), "WriteObject"); CodeBuilder cb = method.CodeBuilder; CodeValueReference obj = cb.DeclareVariable (targetType, method.GetArg(1).CastTo (targetType)); cb += method.GetArg(0).Call ("WriteStartElement", Exp.Literal (targetType.Name)); foreach (FieldInfo field in targetType.GetFields (BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance)) cb += method.GetArg(0).Call ("WriteElementString", Exp.Literal (field.Name), obj[field].CallToString()); cb += method.GetArg(0).Call ("WriteEndElement"); Console.WriteLine (cls.PrintCode ()); Type t = cls.CreateType (); return (ISerializer) Activator.CreateInstance (t); } } public class Data { int a = 2; string b = "hi!"; byte c = 44; } Notice how "obj[field]" is used to reference a field of an object (obj["fieldName"] would also be ok). Notice also that the generator picks the correct WriteElementString overload according to the parameter number and types. This is what PrintCode writes:
public class SerializerForData : Test+ISerializer { System.Void WriteObject (System.Xml.XmlWriter arg0, System.Object arg1) { Data v0; v0 = ((Data)arg1); arg0.WriteStartElement ("Data"); arg0.WriteElementString ("a", v0.a.ToString ()); arg0.WriteElementString ("b", v0.b.ToString ()); arg0.WriteElementString ("c", v0.c.ToString ()); arg0.WriteEndElement (); } } The source code of the generator together with some examples can be downloaded from here. Beware that not everything has been tested and it may generate wrong IL in some cases. If you find any issues drop me an email.

Now, let's keep working on the serializer...