Entwickler-Ecke
Basistechnologien - C#-Code aus externer Textdatei ausführen
KanneM - Mo 19.03.12 12:07
Titel: C#-Code aus externer Textdatei ausführen
Liebe Community,
Ich suche schon lange nach einer (hoffentlich existierenden) Lösung für mein Problem, habe aber nie etwas passendes gefunden:
Ich möchte gerne, dass ein Programm einen C#-Code aus z.B. einer Textdatei einliest und anschließend ausführt (Annahme: Code ist fehlerfrei). Also praktisch ein extrerner Code den man in ein Hauptprogramm integriert, jedoch dann variabel... Existiert so eine Möglichkeit überhaupt oder ist das unlösbar? O.o
Mit freundlichen Grüßen,
Kanne
daeve - Mo 19.03.12 12:11
Für was brauchst du den so was ?
gewisse Teile des Codes die anpassbar sein müssen, kann man über ein Konfigurationsfile erledigen...
Ralf Jansen - Mo 19.03.12 12:21
Einfach den Code durch den Compiler jagen(siehe z.b.
hier [
http://support.microsoft.com/kb/304655/de])? Der kompilierte Code sollte dann irgendeiner Definition folgen damit du weißt wie das Kompilat dann auszuführen ist. Also zum Beispiel könnten die Klassen in diesem Code eine bestimmtes Interface implementieren nach dem du im Kompilat suchen kannst um dann eine bestimmte Methode an diesem Interface aufzurufen um in auszuführen.
KanneM - Mo 19.03.12 15:47
Habs mal ausprobiert, klappt wunderbar =)
Nur eins noch: Das direkte einbinden in die aktuelle Anwendung geht nicht, oder? Also quasi: "FuehreAus(string CodeString)"
Ich meine klar, "http://blogs.msdn.com/b/thottams/archive/2006/08/16/701872.aspx" und dann die .exe ausführen lassen geht, aber es wäre doch schöner wenn die Anwendung direkt den String-Code ausführen würde.
MfG,
Kanne
Ralf Jansen - Mo 19.03.12 16:02
Zitat: |
aber es wäre doch schöner wenn die Anwendung direkt den String-Code ausführen würde. |
Bei diesem Code aus deinem Link sollte es doch eigentlich bei dir klingeln was zu ändern wäre um deinem Wunsch nahe zu kommen.
C#-Quelltext
1: 2: 3: 4: 5:
| CompilerParameters cp = new CompilerParameters(); cp.GenerateExecutable = true; cp.OutputAssembly = "Result.exe"; cp.GenerateInMemory = false; CompilerResults cr = provider.CompileAssemblyFromSource(cp, sourcecode); |
KanneM - Mo 19.03.12 16:06
Ralf Jansen hat folgendes geschrieben : |
Zitat: | aber es wäre doch schöner wenn die Anwendung direkt den String-Code ausführen würde. |
Bei diesem Code aus deinem Link sollte es doch eigentlich bei dir klingeln was zu ändern wäre um deinem Wunsch nahe zu kommen.
C#-Quelltext 1: 2: 3: 4: 5:
| CompilerParameters cp = new CompilerParameters(); cp.GenerateExecutable = true; cp.OutputAssembly = "Result.exe"; cp.GenerateInMemory = false; CompilerResults cr = provider.CompileAssemblyFromSource(cp, sourcecode); | |
Ich denke schon... Bin mir aber nicht sicher, in unseren Vorlesungen sind wir noch nicht so tief eingetaucht.
C#-Quelltext
1: 2: 3: 4: 5:
| CompilerParameters cp = new CompilerParameters(); cp.GenerateExecutable = false; cp.GenerateInMemory = true; CompilerResults cr = provider.CompileAssemblyFromSource(cp, sourcecode); |
Würde das dann so funktionieren?
LG,
Kanne
Ralf Jansen - Mo 19.03.12 16:18
Theoretisch. In den CompilerResults solltest du jetzt deine Assembly finden.
KanneM - Mo 19.03.12 17:47
Ralf Jansen hat folgendes geschrieben : |
Theoretisch. In den CompilerResults solltest du jetzt deine Assembly finden. |
D.h. ich könnte es jetzt wie aufrufen? Sorry, aber ich bin nochnet so fit in dem Gebiet, arbeite weng vor...
KanneM - Di 20.03.12 13:12
Also ich hab mal weng was durchprobiert, letztenendes endet es immer in einem Fehler... Glaube auch nicht dass ich des richtig angesetzt habe...
Könntest du mir vllt zeigen wie der Code aussehen würde, dann könnte ich mein Projekt bis nächste Woche noch fertig stellen =/
LG,
Kanne
Th69 - Di 20.03.12 14:32
Hallo KanneM,
machen wir es besser umgekehrt. Du präsentierst deinen bisherigen (kompilierfähigen) Code und dann schauen wir zusammen darauf und geben dir Tipps.
KanneM - Di 20.03.12 16:22
Wiegesagt, die Änderung die ich oben gepostet habe ist das was funktioniert, das dann aber zum laufen bringen ist die Schwierigkeit. Ich hab mit Activator.Create... und ... .CreateInstance rumprobiert, ein Assemblyverweis brachte auch nicht das gewünschte Resultat.
Wird wohl noch zu hcoh für mich sein, aber ich will das jetzt wenigstens fertig bekommen =D
-------------------------------------------------------------------------------------------------
EDIT: Hab jetzt nochmal was anderes gefunden:
http://msdn.microsoft.com/de-de/library/ms173139.aspx
Hierbei wird wohl aber eine exe Datei geladen, also genau das was ich eigentlich nicht will.
Auch hier
http://stackoverflow.com/questions/5997995/in-net-4-0-how-do-i-sandbox-an-in-memory-assembly-and-execute-a-method
habe ich einiges ausprobiert, aber wie soll ich einen Pfad vom Assembly angeben, wenn doch nur der Code kompiliert wird?
LG
Th69 - Mi 21.03.12 18:17
Hallo KanneM,
was genau willst du denn ausführen? Eine einzelne statische Methode oder aber eine Klasse instantiieren und dann eine Methode davon aufrufen?
Im 2.Link (d.h. den ich auch gepostet habe) sind die entscheidenden Zeilen
C#-Quelltext
1: 2: 3:
| var instanceOfSomeClass = compilerResults.CompiledAssembly.CreateInstance(className);
instanceOfSomeClass.GetType().GetMethod("DoSomething").Invoke(instanceOfSomeClass, null); |
Wobei
className dann der Klassenname ist und
"DoSomething" die aufzurufende Methode darstellt (beide vom Typ
string).
Für eine statische Methode kannst du den ersten Parameter bei
Invoke dann auf
null setzen.
Wenn das auch nicht hilft, dann poste doch mal, was du genau kompilieren willst (dies muß natürlich eine komplette Klasse inkl. Referenzen sein).
KanneM - Mi 21.03.12 19:16
Ich bekomme jetzt noch einen Fehler in der zweiten Zeile von deinem Post:
Zitat: |
System.NullReferenceException wurde nicht behandelt.
Message=Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt.
Source=Test
StackTrace:
bei CodeDomSample.CSharpCodeExample() in C:\Users\XXX\Documents\visual studio 2010\Projects\TestConsole\Test\Program.cs:Zeile 194.
bei CodeDomSample.Main() in C:\Users\XXX\Documents\visual studio 2010\Projects\TestConsole\Test\Program.cs:Zeile 206.
bei System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
bei System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
bei Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
bei System.Threading.ThreadHelper.ThreadStart_Context(Object state)
bei System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
bei System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
bei System.Threading.ThreadHelper.ThreadStart()
InnerException:
|
oder
Zitat: |
Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt. |
Der 'externe' Code sieht so aus:
C#-Quelltext
1:
| String sourcecode = "\nusing System;\npublic class Sample \n{\n static void Main()\n {\n Console.WriteLine(\"This is a test\");\n }\n}" |
Und die verarbeitende Methode: (genau wie hier:
http://blogs.msdn.com/b/thottams/archive/2006/08/16/701872.aspx)
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47:
| public void CSharpCodeExample() {
String sourcecode = "\nusing System;\npublic class Sample \n{\n static void Main()\n {\n Console.WriteLine(\"This is a test\");\n }\n}";
CSharpCodeProvider provider = new CSharpCodeProvider();
CompilerParameters cp = new CompilerParameters();
cp.GenerateExecutable = false;
cp.GenerateInMemory = true;
CompilerResults cr = provider.CompileAssemblyFromSource(cp, sourcecode);
if (cr.Errors.Count > 0) {
Console.WriteLine("Errors building {0} into {1}", sourcecode, cr.PathToAssembly);
foreach (CompilerError ce in cr.Errors) {
Console.WriteLine(" {0}", ce.ToString());
Console.WriteLine();
}
}
else {
Console.WriteLine("Source \n \n {0} \n \n \n built into {1} successfully.", sourcecode, cr.PathToAssembly);
var instanceOfSomeClass = cr.CompiledAssembly.CreateInstance("Sample"); instanceOfSomeClass.GetType().GetMethod("Main").Invoke(instanceOfSomeClass, null); }
return;
} |
PS: Habe bei Invoke den Parameter wie du gesagt hast auch auf null gesetzt, ging trotzdem nicht =(
Verstehe ich eigentlich nicht ganz warum das jetzt nicht geht :x
LG,
Kanne
Ralf Jansen - Mi 21.03.12 19:32
Deine Methode in der zu kompilierenden Klasse ist statisch (Nebenbei die solltest du auch nicht Main nennen. So sollte nur die Start Methode eines Executables heißen aber nicht irgendeine Methode die man aufrufen kann) Dein Code könnte bereits funktionieren wenn du mal das static weg nimmst. Ansonsten die Methode einfach nicht über eine Instanz aufrufen sondern direkt über die Klasse z.B. in etwa so
C#-Quelltext
1:
| cr.CompiledAssembly.GetType("Sample").GetMethod("DoSomething", BindingFlags.Public | BindingFlags.Static).Invoke(null, null); |
Th69 - Mi 21.03.12 19:35
Hallo,
am besten, du teilst den Code in mehrere Zeilen auf.
Ich nehme an, daß er bei
GetMethod("Main") null zurückgibt, da deine Methode nicht
public ist.
Also besser darauf abtesten:
C#-Quelltext
1: 2: 3:
| MethodInfo methodInfo = instanceOfSomeClass.GetType().GetMethod("Main"); if (methodInfo != null) methodInfo.Invoke(instanceOfSomeClass, null); |
Ansonsten kannst du bei
GetMethod auch noch
BindingFlags übergeben:
C#-Quelltext
1: 2:
| BindingFlags flags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; MethodInfo methodInfo = instanceOfSomeClass.GetType().GetMethod("Main", BindingFlags); |
Am besten du schaust dafür in der MSDN nach...
KanneM - Mi 21.03.12 19:58
Ich habe jetzt mal die Version von Ralf Jansen ausprobiert, funktioniert super! =D
Schau mir jetzt auchmal die anderen Lösungen an und experimentier nochweng mit dem Code damit ich das dann auch komplett alles versteh...
Danke an euch und gerade dich Th69 für die Geduld :D
LG,
Kanne
KanneM - Mi 21.03.12 20:52
Ok, neues Problem...
EDIT: Hat sich erledigt, habs selbst hinbekommen ;)
Lg
Ralf Jansen - Mi 21.03.12 21:18
Einfach mal richtig den Exceptiontext lesen da stehts im Klartext.
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!