mikrocontroller.net

Forum: PC-Programmierung C# Zur Laufzeit Modul kompilieren und darauf zugreifen


Autor: Peterle Anonym (Firma: keine) (wanderameise)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also,

zur Laufzeit erstelle ich ein cs file, welches eine simple klasse 
enthält:
using System;
namespace WindowsFormsApplication1
{    
  class bla  
  {
    public int xyz;    
    public bla(){}
                publis void setbla(int val){xyz = val;}
         }
}

Ich muss nun auf diese Klasse zugreifen können. Also kompiliere ich 
diese und erstelle eine DLL. Das sollte doch prinzipiell machbar sein, 
mit der obigen Klasse oder?

Dazu habe ich dieses Beispiel verwendet und anstatt einer EXE, eine DLL 
daraus gemacht http:
http://msdn.microsoft.com/en-us/library/system.cod...
Hat auch soweit geklappt.

Wie binde ich diese nun zur Laufzeit ein? Muss ich dazu eine neue Domäne 
anlegen? Weil wenn ich mir das so anschaue, verstehe ich nur Bahnhof!

Kann mir jemand weiterhelfen?

Autor: Christian R. (mrrotzi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn du das Assembly als DLL vorliegen hast, kannst mit Reflection alles 
damit tun!
var assembly = System.Reflection.Assembly.LoadFrom(@"c:\assembly.dll");

aus dem assembly ladest du die Typendefinitionen:
var type = assembly.GetType("Klassenname");

und mit Activator kannst du dann eine Instanz der Klasse erzeugen
object instance = Activator.CreateInstance(type);


Warum aber überhaupt on the fly assemblies erzeugen??? ? ?? ... ?

Grüße,
Christian

Autor: Peterle Anonym (Firma: keine) (wanderameise)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das ist so eine Sache. Rufe zur Laufzeit eine exe auf, die ein file 
parst und daraus eben diese Klasse erstellt. Wüsste nicht wie ich es 
anders lösen könnte. Aber den c code, aus dem die exe erstellt wurde, zu 
portieren, würde etwas länger dauern, deswegen dieser weg.
ok werde es mal testen.

Autor: __tom (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peterle Anonym schrieb:
> Muss ich dazu eine neue Domäne
> anlegen?

nur wenn du das assembly wieder entladen möchtest, es gibt (zumindest 
bis .net35) keinen mechanismus ein einmal geladenes assemlby wieder zu 
entladen. das zerstören einer appdomain ginge aber.

Autor: Markus Volz (valvestino)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi Peterle,

.net hat ein mächtiges Feature: Reflection. Es bietet die Lösung für 
dein(e) Problem(e). Du müßtest Dir zunächst eine Instanz des Compilers 
über System.CodeDOM.CodeDOMProvider.CreateCompiler("CSharp") und über 
deren Methode CompileSourceFromFile (...FromSource,...FromDOM) ein 
Assembly-Objekt erzeugen. Über Reflection kannst Du dann Objekte von 
Klassen aus Deiner Assembly instanziieren und Methoden derselben 
aufrufen.

Eine andere Möglichkeit wäre, die Methoden der Objekte aus der zur 
Laufzeit erzeugten Assembly über ein Interface anzusprechen, das 
natürlich zur Compile-Zeit Deines Hauptprogramms vorhanden sein muß. 
Dann sparst Du Dir den Methodenaufruf über Reflection.

Du solltest auf jeden Fall mal die MSDN-Doku zum Thema konsultieren, da 
es leider einige Parameter bei den beteiligten Klassen gibt, die passend 
versorgt sein wollen.

Gruß
Markus

Autor: peterle (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christian R. schrieb:
> Wenn du das Assembly als DLL vorliegen hast, kannst mit Reflection alles
> damit tun!
> var assembly = System.Reflection.Assembly.LoadFrom(@"c:\assembly.dll");
>
> aus dem assembly ladest du die Typendefinitionen:
> var type = assembly.GetType("Klassenname");
>
> und mit Activator kannst du dann eine Instanz der Klasse erzeugen
> object instance = Activator.CreateInstance(type);
>
>
> Warum aber überhaupt on the fly assemblies erzeugen??? ? ?? ... ?
>
> Grüße,
> Christian

Wie greife ich dann auf die Methode der klasse zu, denn zur 
Kompilierzeit ist diese nicht bekannt und der Compiler meckert:
...
instance.test(33);

test ist nicht bekannt in diesem kontext!

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peterle Anonym schrieb:
> Aber den c code,

C? Ich dachte C#?

Autor: Peterle Anonym (Firma: keine) (wanderameise)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Markus Volz schrieb:
> Hi Peterle,
>
> .net hat ein mächtiges Feature: Reflection. Es bietet die Lösung für
> dein(e) Problem(e). Du müßtest Dir zunächst eine Instanz des Compilers
> über System.CodeDOM.CodeDOMProvider.CreateCompiler("CSharp") und über
> deren Methode CompileSourceFromFile (...FromSource,...FromDOM) ein
> Assembly-Objekt erzeugen. Über Reflection kannst Du dann Objekte von
> Klassen aus Deiner Assembly instanziieren und Methoden derselben
> aufrufen.
>
> Eine andere Möglichkeit wäre, die Methoden der Objekte aus der zur
> Laufzeit erzeugten Assembly über ein Interface anzusprechen, das
> natürlich zur Compile-Zeit Deines Hauptprogramms vorhanden sein muß.
> Dann sparst Du Dir den Methodenaufruf über Reflection.
>
> Du solltest auf jeden Fall mal die MSDN-Doku zum Thema konsultieren, da
> es leider einige Parameter bei den beteiligten Klassen gibt, die passend
> versorgt sein wollen.
>
> Gruß
> Markus

hi,

ja also kompiliert habe ich das ganze zur laufzeit schon und eine dll 
wurde auch erstellt. das hab ich folgendermaßen gemacht:
FileInfo sourceFile = new FileInfo(sourceName);
CodeDomProvider provider = null;
provider = CodeDomProvider.CreateProvider("CSharp");
CompilerParameters cp = new CompilerParameters();
cp.GenerateExecutable = false;
//cp.ReferencedAssemblies.Add("System.Core.dll");
// Specify the assembly file name to generate.
String exeName = String.Format(@"{0}\{1}.dll",
                    System.Environment.CurrentDirectory,
                    sourceFile.Name.Replace(".", "_"));
cp.OutputAssembly = exeName;

// Save the assembly as a physical file.
cp.GenerateInMemory = true;

// Set whether to treat all warnings as errors.
cp.TreatWarningsAsErrors = false;

// Invoke compilation of the source file.
CompilerResults cr = provider.CompileAssemblyFromFile(cp,
    sourceName);



sollte so passen. wobei ich nicht bei allen parametern sicher bin

Autor: Peterle Anonym (Firma: keine) (wanderameise)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Klaus Wachtler schrieb:
> Peterle Anonym schrieb:
>> Aber den c code,
>
> C? Ich dachte C#?

nein. ich rufe aus C# eine exe auf. DIESE wurde in C erstellt, sonst 
wäre es ja halb so wild ;)

Autor: Peterle Anonym (Firma: keine) (wanderameise)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christian R. schrieb:
> Wenn du das Assembly als DLL vorliegen hast, kannst mit Reflection alles
> damit tun!
>
>
> var assembly = System.Reflection.Assembly.LoadFrom(@"c:\assembly.dll");
> 
>
> aus dem assembly ladest du die Typendefinitionen:
>
>
> var type = assembly.GetType("Klassenname");
> 

wenn ich hier den klassennamen reinschreibe, liefert mir GetType null 
zurück
und:

> und mit Activator kannst du dann eine Instanz der Klasse erzeugen
>
>
> object instance = Activator.CreateInstance(type);
> 

das schlägt fehl.

Ohne Parameter liefert GetType schon mal nicht null, sondern 
System.Reflection.RuntimeAssembly. Dann aber sagt er

No parameterless constructor defined for this object

stimmt vll was mit meiner DLL nicht, bzw der darin enthaltenen klasse?

Wenn ich mir GetType(string)-Methode anschaue, steht in der msdn, dass 
dieser ein  AssemblyQualifiedName erwartet... oh man

Autor: Markus Volz (valvestino)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Na ja, Du musst beim Klassenname zumindest mal den Namespace mit 
angeben, sonst wird das nichts, gemäß Deinem obigen Beispiel: 
WindowsFormsApplication1.bla.

Wieso versuchst Du eigentlich, die Assembly als Datei von der Platte zu 
laden? Das geht natürlich, aber Du hast sie im CompilerResult-Objekt 
bereits als Objekt vorliegen und kannst direkt damit arbeiten. Zum 
Compilieren musst Du den Sourcecode auch nicht in eine Datei schreiben. 
Du kannst auch ein String-Objekt compilieren.

Aus Deinen Infos oben geht nicht so klar hervor, ob die DLL nun eine 
Windows-DLL oder eine .net-Assembly ist. Die haben zwar beide die selbe 
Dateinamenserweiterung (.dll), haben aber sonst nichts gemeinsam.

Eine Windows-DLL kannst Du mittels P-Invoke laden und Funktionen daraus 
ansprechen. Für .net-Assemblies ist Reflection vorgesehen.

Gruß
Markus

Autor: Peterle Anonym (Firma: keine) (wanderameise)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
wie hier beschrieben:
Beitrag "Re: C# Zur Laufzeit Modul kompilieren und darauf zugreifen"

handelt es sich um ein assembly.

>aber Du hast sie im CompilerResult-Objekt
>bereits als Objekt vorliegen und kannst direkt damit arbeiten

meinst du ich kann direkt mit dieser Referenz arbeiten:
CompilerResults cr = provider.CompileAssemblyFromFile(cp,
    sourceName);


>Compilieren musst Du den Sourcecode auch nicht in eine Datei schreiben.
>Du kannst auch ein String-Objekt compilieren.

naja die zu kompilierende Datei wird ja durch ein externes Programm zur 
Laufzeit erzeugt. wüsste nicht wie ich da einen string übergeben 
könnte?!

Autor: Markus Volz (valvestino)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok, da der Sourcecode extern erzeugt wird, ist CompileAssemblyFromFile 
natürlich die bessere Wahl.

Die Objekte des Typs CompilerResults haben ein Property CompiledAssembly 
vom Typ Assembly. Von diesem Assembly-Objekt kannst Du dann wieder die 
Methode CreateInstance aufrufen, um Instanzen von Deiner Klasse zu 
erhalten. Der Klassenname umfasst, wie bereits oben erwähnt, neben dem 
Klassennamen natürlich auch den Namespace!

Gruß
Markus

Autor: Peterle Anonym (Firma: keine) (wanderameise)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Markus Volz schrieb:
> Ok, da der Sourcecode extern erzeugt wird, ist CompileAssemblyFromFile
> natürlich die bessere Wahl.
>
> Die Objekte des Typs CompilerResults haben ein Property CompiledAssembly
> vom Typ Assembly. Von diesem Assembly-Objekt kannst Du dann wieder die
> Methode CreateInstance aufrufen, um Instanzen von Deiner Klasse zu
> erhalten. Der Klassenname umfasst, wie bereits oben erwähnt, neben dem
> Klassennamen natürlich auch den Namespace!
>
> Gruß
> Markus

ahh, cool, mit dem namespace klappt es, wie trivial...

Aber wenn ich jetzt einen member (methode, variable) aufrufen will, 
meckert er, da er sie ja zur compile-zeit nicht kennt!!
int x = instance.test;

Autor: Christian R. (mrrotzi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das geht auch über Reflection:
var method = type.GetMethod("test");
method.Invoke(instance, new object[] { });


Grüße,
Christian

Autor: Peterle Anonym (Firma: keine) (wanderameise)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ahhh danke, klappt soweit.

Kann es sein, dass ich für jede methode die ich aufrufen will eine neues 
instance erzeugen muss via CreateInstance?
/// mit parameter
            object instance = Activator.CreateInstance(type);
            var method = type.GetMethod("abc");
            method.Invoke(instance, new object[] {7});
// mit rückgabewert
            object instance1 = Activator.CreateInstance(type);
            var method1 = type.GetMethod("add");
            var b = method1.Invoke(instance1, new object[] {});


Autor: Läubi .. (laeubi) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peterle Anonym schrieb:
> ahhh danke, klappt soweit.
>
> Kann es sein, dass ich für jede methode die ich aufrufen will eine neues
> instance erzeugen muss via CreateInstance?
1) Nein wie kommst du darauf?
2) Wie wäre es eigentlich dem Rat mal zu folgen sich in das Themengebiet 
einzulesen? Alternativ bitte den vollständigen Code liefern das wir dir 
das hier jetzt nicht Stück für Stück zusammenprogrammieren müssen...

Autor: Peterle Anonym (Firma: keine) (wanderameise)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hat sich geklärt, es klappt alles soweit wie gewünscht.
Danke Leute!!

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.