PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [C#] Code zur Laufzeit generieren und ausführen


The_Invisible
2008-01-06, 18:38:12
hallo,

gibt es eine einfache methode in C# code zur laufzeit zu generieren und auszuführen ala eval() in php, python, js usw?

da C# ja erst zur laufzeit kompiliert wird sollte das ja möglich sein oder nicht?

und dann wäre da noch was: kann man funktionen/methoden zur laufzeit aufrufen? zb hat man einen string "functest" und könnte damit die funktion/methode "functest()" aufrufen zb ala System.ExecuteMethod(string methodname)

so das wärs :D

mfg

TheGamer
2008-01-06, 18:59:33
Schau dir mal die Namespaces

System.CodeDom.Compiler;
Microsoft.CSharp;

an.

CSharpCodeProvider -> CreateCompiler

ICodeCompiler-> CompileAssemblyFromSource(string)


Das war jetzt eine grobe Aussage aber ich denke ich habe die namespaces und Klassen namentlich denke ich getroffen, frei aus dem Kopf.

Es sollte dich auf den richtigen Pfad lenken :D

Gnafoo
2008-01-06, 20:33:26
Das ganze Zeug im Reflection.Emit-Namespace könnte auch interessant sein (MethodBuilder etc.). Viel mehr kann ich dazu aber auch nicht sagen. Hab das nie gebraucht, aber den Namespace hatte ich jetzt gleich dazu im Kopf XD.

Bietchiebatchie
2008-01-07, 04:24:07
Generieren geht zwar, ist allerdings mit enormen Aufwand verbunden, da man mehr oder weniger den IL-Code selber zusammenfrickeln muss. Wenn es dich wirklich interessiert, kannst du mal schauen, was für Frameworks zum Generieren von Code gibt gibt; das letzte mal als ich danach geschaut habe, waren die meisten davon nicht so wahnsinnig mächtig und immer noch umständlich.

Aufrufen von Code mittels strings ist damit verglichen eher Kindergarten:

Falls im Namespace xyz die Klasse C mit Methode foo existiert:

Type.GetType("xyz.C").InvokeMember("foo", parameter)

oder

Type.GetType("xyz.C").GetMember("foo").Invoke( parameter ...).

Weiß das nicht auswendig, eins von beiden müßte ungefähr richtig sein. Bin leider grad zu faul, um zu testen, sorry :/

Gnafoo
2008-01-07, 14:45:56
Generieren geht zwar, ist allerdings mit enormen Aufwand verbunden, da man mehr oder weniger den IL-Code selber zusammenfrickeln muss.

Die Dokumentation zu den Klassen die "TheGamer" vorgeschlagen hat klingt aber gar nicht danach. Wenn ich diese richtig überflogen habe, kann man mit dem CSharpCodeProvider einfach beliebigen Code aus einem String kompilieren lassen. Daraufhin bekommt man ein CompilerResults-Objekt, aus dem man nach erfolgreicher Kompilierung die kompilierte Assembly herausfischen kann.

Die Assembly kann man dann laden, sich einen Typ aus der Assembly holen und dann munter Methoden des Typs ausführen.

Klingt doch eigentlich recht einfach. Klar nicht mit eval(...) zu vergleichen, dafür ist es aber vermutlich besser für größere Sachen geeignet. Für kleine Sachen ist dein Ansatz über InvokeMember/Invoke sicher besser.

TheGamer
2008-01-07, 14:50:19
Die Dokumentation zu den Klassen die "TheGamer" vorgeschlagen hat klingt aber gar nicht danach. Wenn ich diese richtig überflogen habe, kann man mit dem CSharpCodeProvider einfach beliebigen Code aus einem String kompilieren lassen. Daraufhin bekommt man ein CompilerResults-Objekt, aus dem man nach erfolgreicher Kompilierung die kompilierte Assembly herausfischen kann.

Die Assembly kann man dann laden, sich einen Typ aus der Assembly holen und dann munter Methoden des Typs ausführen.

Klingt doch eigentlich recht einfach. Klar nicht mit eval(...) zu vergleichen, dafür ist es aber vermutlich besser für größere Sachen geeignet. Für kleine Sachen ist dein Ansatz über InvokeMember/Invoke sicher besser.

Genau so ist es. Du kannst jeglichen Code zusammenstückeln und kompilieren lassen, du erhälst eine komplette List der Fehler und Warnings -> wenn du willst bzw. ein Assembly mit dem du es treiben kannst bis du rot wirst. Nix IL only, wo sind wir denn.

Beispiel schnell was gebastelt:

private Assembly CreateAssembly( string SourceCode )
{
CodeDomProvider codeProvider = new CSharpCodeProvider( );
ICodeCompiler compiler = codeProvider.CreateCompiler( );

//add compiler parameters
CompilerParameters compilerParams = new CompilerParameters( );
compilerParams.CompilerOptions = "/target:library";
compilerParams.GenerateExecutable = false;
compilerParams.GenerateInMemory = true;
compilerParams.IncludeDebugInformation = false;

compilerParams.ReferencedAssemblies.Add( "mscorlib.dll" );
compilerParams.ReferencedAssemblies.Add( "System.dll" );
compilerParams.ReferencedAssemblies.Add( "System.Data.dll" );
compilerParams.ReferencedAssemblies.Add( "System.Drawing.dll" );
compilerParams.ReferencedAssemblies.Add( "System.Xml.dll" );
compilerParams.ReferencedAssemblies.Add( "System.Windows.Forms.dll" );

CompilerResults results = compiler.CompileAssemblyFromSource(compilerParams, SourceCode );

return results.CompiledAssembly;
}

und

private void CallEntry( Assembly assembly, string entryPoint )
{
try
{
Module[] mods = assembly.GetModules( false );
Type[] types = mods[0].GetTypes( );

foreach ( Type type in types )
{
MethodInfo mi = type.GetMethod( entryPoint, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static );
if ( mi != null )
{
if ( mi.GetParameters( ).Length == 1 )
{
if ( mi.GetParameters( )[0].ParameterType.IsArray )
{
string[] par = new string[1];
mi.Invoke( null, par );
}
}
else
{
mi.Invoke( null, null );
}
return;
}
}
}
catch ( Exception )
{

}

}

Zusammen mit einer gui -> Mehrzeilige Textbox + button auf dem run steht ;)

in der textbox steht

using System;
using System.Windows.Forms;

namespace test
{
class mytest
{
void Main()
{
MessageBox.Show("Test");
}
}
}

klickt man nun auf run wird CreateAssembly mit dem textboxinhalt gefüttert und ratet mal was dann passiert, richtig eine messagebox mit inhalt test erschein ;)

The_Invisible
2008-01-07, 19:18:08
ok, großes danke an alle, ihr habt mir SEHR weitergeholfen.

bin mal auf die performance gespannt wenn man während dem start des programmes auch noch was dynamisch kompilieren lässt.

mfg

M$
2008-01-07, 19:52:16
Wenn man garnicht weiter weiß, dimensioniert man z.B. schlichtweg eine Variable falsch und handelt die Exception.... :)

M$
2008-01-07, 19:53:33
Wenn man garnicht weiter weiß, deklariert man z.B. schlichtweg eine Variable falsch und handelt die Exception.... :)

Gast
2008-01-07, 19:54:13
So wie diese Datenbank X-D

Plutos
2008-02-05, 07:29:10
Funktioniert das in der Art auch in Visual Basic 2008?