Dynamisches Laden von Klassen

Tikonteroga

Erfahrenes Mitglied
Hallo,

ich habe mit einem Code Generator zwei Klassen eines unterschiedlichen Typs als cs-Datei (C#) generiert. Wie kann ich diese Klassen denn nun zur Laufzeit laden und instanzieren so dass sie mir im Code als Objekte der Klasse Object zur Verfügung stehen ?

Gruß

Tikonteroga
 

sheel

I love Asm
Hi

Der Code ist also zur Kompilierzeit vom eigentlichen Programm noch nicht bekannt?
Gibts irgendein einheitliches Interface/Methodennamen etc.?
 

Tikonteroga

Erfahrenes Mitglied
Hallo,

also das laufende Programm erzeugt die beiden Klassen über eine externe Konsolenanwendung. Der Name der Klassen sowie die Methoden sind mir bekannt.

Für die Verwendung der Klassen hatte ich entweder an ein Interface gedacht oder an ein Aquivalent zu JAVA Reflection.

Ich habe mal meinen aktuellen Stand hochgeladen. Konnte aber noch nicht testen, ob es so auch funktioniert, weil ich beim Testen noch an den Vorroutinen feststecke.

Code:
private void LoadGeneratedClasses()
        {
            CompilerParameters options = new CompilerParameters();
            options.GenerateExecutable = false;
            options.GenerateInMemory = true;

            CSharpCodeProvider codeProvider = new CSharpCodeProvider();

            string[] filenames = new string[] 
            {
                Path.Combine(this.StartInfo.OutputDirectory, "Parser.cs"),
                Path.Combine(this.StartInfo.OutputDirectory, "Scanner.cs")
            };

            this.compilerResults = codeProvider
                .CompileAssemblyFromFile(options, filenames);
        }

Code:
public Type Parser
        {
            get
            {
                return (this.compilerResults != null) 
                    ? this.compilerResults.CompiledAssembly.GetType("Parser")
                    : null;
            }
        }

        public Type Scanner
        {
            get
            {
                return (this.compilerResults != null) 
                    ? this.compilerResults.CompiledAssembly.GetType("Scanner")
                    : null;
            }
        }
 

Tikonteroga

Erfahrenes Mitglied
Hallo,

also ich bin jetzt inzwischen etwas weiter gekommen. Aber ich stehe jetzt vor folgendem Problem. Vielleicht hat ja jemand eine Idee bzw. erkennt den Fehler.

In der generierten Datei "Parser.cs" wird folgende Assembly eingebunden.

Code:
using X.Y;

Wenn jedoch folgenden Code ausführe, erhalte ich eine Fehlermeldung, dass der Namespace Y im Namespace X nicht gefunden werden konnte.

Ich habe jedoch die DLL X.Y.dll, die den Namensraum enthält als zu verlinkende Ressource mit dem absoluten Pfad angegeben.

Code:
options.LinkedResources.AddRange(this.StartInfo.LinkedRessources.ToArray());

Hier ist mal ein Ausschnitt aus meinem Code. Leider kann ich aus Geheimhaltungsgründen nicht den vollständigen Code hochladen.

Code:
CompilerParameters options = new CompilerParameters();
options.GenerateExecutable = false;
options.GenerateInMemory = true;
options.LinkedResources.AddRange(this.StartInfo.LinkedRessources.ToArray());
            
CSharpCodeProvider codeProvider = new CSharpCodeProvider();

string[] filenames = new string[] 
{
     Path.Combine(this.StartInfo.OutputDirectory, "Parser.cs"),
     Path.Combine(this.StartInfo.OutputDirectory, "Scanner.cs")
};

this.compilerResults = codeProvider
     .CompileAssemblyFromFile(options, filenames);
 

Tikonteroga

Erfahrenes Mitglied

Hallo,

ich habe jetzt mal zur Vereinfachung versucht nur eine der beiden Klassen zu kompilieren.

Diese Klasse verwendet folgende Namespaces.

Code:
using System;
using System.IO;
using System.Collections;

Hierfür habe ich folgende Assemblies als LinkedResources angegeben.

Code:
options.LinkedResources.Add("System.dll");
options.LinkedResources.Add("mscorlib.dll");

Jetzt habe ich jedoch folgende Probleme.

In der Klasse die ich kompilieren möchte ist u. a. folgender Aufruf.

Code:
throw new FatalError("...");

Wenn ich die Datei kompiliere erhalte ich die Fehlermeldung das "FatalError" nicht gefunden wurde. Weiss jemand auf welche DLL ich verweisen muss, damit ich FatalError bekannt machen kann. Ich konnte auch bei Google nichts über die Klasse (Exception?) finden.

Mir ist auch aufgefallen, dass beim Konsolenaufruf von csc.exe die von mir angegeben verlinkten Ressource nicht auftauchen, könnte auch das zu meinem weiter oben geschilderten Problem führen ?
 

Shakie

Erfahrenes Mitglied
FatalError ist keine mir bekannte Standard-.Net-Klasse. Alle Ausnahmen enden nach MS-Namenskonvention auf "Exception".

Aber lass mich kurz zusammenfassen, was du tust, um sicherzugehen, dass ich verstehe wo das Problem liegt:
  1. Du erstellst mit deinem C#-Programm eine Textdatei, die gültigen C#-Code enthält und eine komplette Klassendefinition beinhaltet
  2. Du kompilierst diese Textdatei, ebenfalls mit deinem C#-Programm und erhälst eine .Net-DLL
  3. Du willst die gerade erstellte DLL in dein Programm laden und eine Instanz der sich darin befindenden Klasse erzeugen?
Stimmt das soweit? An welchem Punkt gibt es Probleme? Bei Punkt 3?
 

Tikonteroga

Erfahrenes Mitglied
Hallo,

das stimmt alles soweit.

Es gab beim Punkt (2.) Probleme, da ich die Dateien nicht kompilieren konnte.

Inzwischen konnte ich das Problem beheben. Mein fehler war, dass ich die Eigenschaft "LinkedResources" verwendet habe, um auf Assemblies zu verweisen. Die richtige Eigenschaft ist jedoch "ReferencedAssemblies".

Falsch:

Code:
options.LinkedResources.Add("System.dll");

Richtig:

Code:
options.ReferencedAssemblies.Add("System.dll");

Ich konnte die beiden Klassen nun erfolgreich kompilieren und habe auch schon mit Reflection eine Instanz erstellen können.
 

Neue Beiträge