[C#] Dynamisch code genereren

Pagina: 1
Acties:

  • maikel
  • Registratie: Januari 2001
  • Laatst online: 20-08 09:32
Ik heb eens zitten kijken naar de System.Reflection.Emit-namespace en volgens mij kun je daar hele leuke dingen mee. Ik vraag me alleen af wat de handigste manier is om dynamisch code te genereren.
Het netst is via de Emit-namespace en de MethodBuilder, PropertyBuilder, etc., maar dan moet je (volgens mij) overal met OpCodes gaan werken en dat is nogal onhandig

Wat mij handiger lijkt, is zelf een cs-file schrijven en daar gewoon dmv bijv.
code:
1
2
3
4
file.WriteLine("if (a == true)\n");
file.WriteLine("{\n");
file.WriteLine("\t <code> \n");
file.WriteLine("}\n");
code naartoe te schrijven.
Nadeel hierbij is dat het makkelijker fout kan gaan.

Heeft iemand hier meer ervaring mee of nog goede ideeen over?

Is de gegenereerde code trouwens ook nog te compilen zonder daarvoor de VS-compiler (csc.exe) voor te moeten gebruiken?

[ Voor 29% gewijzigd door maikel op 22-05-2003 11:51 ]


  • whoami
  • Registratie: December 2000
  • Laatst online: 10:17
maikel schreef op 22 mei 2003 @ 11:49:
Is de gegenereerde code trouwens ook nog te compilen zonder daarvoor de VS-compiler (csc.exe) voor te moeten gebruiken?
Welke compiler zou je anders wel willen gaan gebruiken?

https://fgheysels.github.io/


  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Reflection.Emit is vooral gericht op compiler bouwers, niet op code generatoren.

Er zijn een aantal methoden om code te genereren, onafhankelijk van de taal waarin je code genereert, en de taal van de code die je genereert. Eigenlijk gebruiken alle methoden onder water de volgende twee mogelijkheden:

1) Tekst genereren (zoals jij voorstelt)
2) Abstract Syntax Trees opbouwen en deze na het opbouwen pretty printen

Of je oplossing 1 nu realiseert via templates, string literals of een template taal, maakt niet zoveel uit. Zoals je zelf al aangeeft is het erg gevoelig voor fouten. Ik had gisteren nog een aardig voorbeeld hiervan: een Java code generator die normaal alleen op Unix systemen wordt gebruikt ging zwaar de fout in toen hij code ging genereren op Microsoft Windows. Waarom? In file paden kwamen \ voor en dat mag natuurlijk niet zomaar in String literals.

Oplossing 2 is op dit punt veel beter omdat je code genereert in een abstracte syntax en de taal waarin je programmeert kan nagaan of deze abstracte syntax wel juist gevormd is. Het heeft echter wel een groot nadeel: het is erg verbose en je ziet slecht wat je nu eigenlijk genereert. Je wilt natuurlijk gewoon C# code in concrete syntax zien en geen vage abstracte syntax.

Omdat de meeste mensen niet de juiste tools gebruiken, laten ze oplossing 2 vallen (behalve in compilerbouw) en kiezen ze voor simpele code generatoren voor oplossing 1. Je ziet dit toegepast in zeer veel generatoren in zeer verschillende talen (van XSLT tot C#).

Als je wel goede tools gebruikt kan je abstracte syntax genereren, terwijl je toch concrete syntax schrijft. Hierover is een aardig paper geschreven: Meta programming with concrete object syntax. We gebruiken deze aanpak om code generatoren te schrijven in Stratego en werken een implementaties van deze filosofie in Java (met Java en XML als te genereren talen) en XSLT (met willekeurige te genereren talen).

Als je geinteresseerd bent in code generatie is het ook leuk om de weblog van John Lam te volgen: http://www.iunknown.com/ .

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • maikel
  • Registratie: Januari 2001
  • Laatst online: 20-08 09:32
whoami schreef op 22 May 2003 @ 11:57:
[...]


Welke compiler zou je anders wel willen gaan gebruiken?
Ik ging er ook al vanuit dat ie nodig was, maar hoopte dat er in het framework zelf ook al een method was om te compilen oid.

[edit]
Die is er dus ook:
code:
1
2
Microsoft.CSharp.CSharpCodeProvider codeProvider = new Microsoft.CSharp.CSharpCodeProvider();
codeProvider.CreateCompiler().CompileAssemblyFromDom(....);

[ Voor 26% gewijzigd door maikel op 22-05-2003 15:26 ]


  • maikel
  • Registratie: Januari 2001
  • Laatst online: 20-08 09:32
mbravenboer schreef op 22 May 2003 @ 12:03:
Reflection.Emit is vooral gericht op compiler bouwers, niet op code generatoren.

Er zijn een aantal methoden om code te genereren, onafhankelijk van de taal waarin je code genereert, en de taal van de code die je genereert. Eigenlijk gebruiken alle methoden onder water de volgende twee mogelijkheden:

1) Tekst genereren (zoals jij voorstelt)
2) Abstract Syntax Trees opbouwen en deze na het opbouwen pretty printen

Of je oplossing 1 nu realiseert via templates, string literals of een template taal, maakt niet zoveel uit. Zoals je zelf al aangeeft is het erg gevoelig voor fouten. Ik had gisteren nog een aardig voorbeeld hiervan: een Java code generator die normaal alleen op Unix systemen wordt gebruikt ging zwaar de fout in toen hij code ging genereren op Microsoft Windows. Waarom? In file paden kwamen \ voor en dat mag natuurlijk niet zomaar in String literals.

Oplossing 2 is op dit punt veel beter omdat je code genereert in een abstracte syntax en de taal waarin je programmeert kan nagaan of deze abstracte syntax wel juist gevormd is. Het heeft echter wel een groot nadeel: het is erg verbose en je ziet slecht wat je nu eigenlijk genereert. Je wilt natuurlijk gewoon C# code in concrete syntax zien en geen vage abstracte syntax.

Omdat de meeste mensen niet de juiste tools gebruiken, laten ze oplossing 2 vallen (behalve in compilerbouw) en kiezen ze voor simpele code generatoren voor oplossing 1. Je ziet dit toegepast in zeer veel generatoren in zeer verschillende talen (van XSLT tot C#).

Als je wel goede tools gebruikt kan je abstracte syntax genereren, terwijl je toch concrete syntax schrijft. Hierover is een aardig paper geschreven: Meta programming with concrete object syntax. We gebruiken deze aanpak om code generatoren te schrijven in Stratego en werken een implementaties van deze filosofie in Java (met Java en XML als te genereren talen) en XSLT (met willekeurige te genereren talen).

Als je geinteresseerd bent in code generatie is het ook leuk om de weblog van John Lam te volgen: http://www.iunknown.com/ .
Wat bedoel je precies met de tweede optie?
Zou je een klein voorbeeldje kunnen geven daarvan? (eventueel in pseudo-code)

Maar in .Net is het dus niet mogelijk om via die Emit-namespace zonder OpCodes te gebruiken ook code te genereren? Die PropertyBuilder, MethodBuilder, etc. zagen er op zich wel handig uit, behalve dan dat ze dus per se OpCodes nodig hebben.

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
maikel: Wat bedoel je precies met de tweede optie?
Daarvoor mag je het paper lezen wat ik linkte ...
Maar in .Net is het dus niet mogelijk om via die Emit-namespace zonder OpCodes te gebruiken ook code te genereren? Die PropertyBuilder, MethodBuilder, etc. zagen er op zich wel handig uit, behalve dan dat ze dus per se OpCodes nodig hebben.
Als je .NET APIs wilt gebruiken voor code generatie, is de CodeDOM de beste optie. Daar is de CodeDOM voor bedoelt. Niet iedereen is er echter even enthousiast over. Zoek maar eens via Google op code generatie en CodeDOM.

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment

Pagina: 1