Hallo,
ich versuche eine Assembly aus einem String zu laden und eine Instanz zu erstellen.
Zum Testen hab ich die StringBuilder Klasse und Assembly genommen.
Die Assembly wird geladen, aber es erstellt mir keine Instanz des Objektes:
Code:
var br = new BinaryReader(new FileStream(typeof(StringBuilder).Assembly.Location, FileMode.Open));
byte[] data = br.ReadBytes((int)br.BaseStream.Length);
br.Close();
var assembly = Assembly.Load(data);
var sb = assembly.CreateInstance("StringBuilder") as StringBuilder;
was mache ich Falsch?
Vielen Dank
C. Anders
Guck dir mal die Stichworte IDisposable und using an.
FileStream hat IDisposable implementiert und sollte nach der Verwendung auch entsprechend disposed werden.
Das gleiche gilt für den BinaryReader. Hier rufst du die Dispose-Methode zwar indirekt über die Close-Methode auf, allerdings wäre es besser, alles, was IDisposable implementiert hat, in einem using-Block zu verwenden, denn danach werden die Ressourcen garantiert (auch bei Exceptions) frei gegeben.
Warum die Instanz nicht erstellt wird:
Ich vermute einfach mal, weil die StringBuilder-Klasse nicht in der Assembly liegt, die liegt in mscorlib.dll
Hab grad bemerkt, dass du die Assembly der Klasse ja vom Typ bekommst. Den nachfolgenden Test kannst du aber trotzdem mal ausprobieren.
Erstelle doch mal testweise eine DLL, wo du einen eigenen Typ drin liegen hast und lasse dir davon eine Instanz erstellen.
Wenn ich dein Vorhaben aber richtig verstanden habe, dann geht das alles auch viel einfacher, in Gewusst wie: Laden und Entladen von Assemblys (C# und Visual Basic) nach zu lesen.
PS: Ok, hab den Fehler.
Du brauchst den vollständigen Namen des Typs, das meint auch den Namespace.
Außerdem hättest du bei deinem Code schon in der ersten Zeile eine Exception erhalten müssen, da Windows den Zugriff auf die mscorlib.dll nicht zu lässt, es ist nur lesender Zugriff erlaubt und das musst du explizit über einen weiteren Parameter im Konstruktor angeben.
So funktioniert es auf jeden Fall und kurz:
var sourceType = typeof(StringBuilder);
var assembly = Assembly.LoadFile(sourceType.Assembly.Location);
var stringBuilderType = assembly.GetType(sourceType.FullName);
var obj = Activator.CreateInstance(stringBuilderType) as StringBuilder;
Wer [...] kann, ist klar im Vorteil.
lock
Alternative fürasync
/await
: https://github.com/loop8ack/AsyncTicketLock
FileStream hat IDisposable implementiert und sollte nach der Verwendung auch entsprechend disposed werden.
Das gleiche gilt für den BinaryReader. Hier rufst du die Dispose-Methode zwar indirekt über die Close-Methode auf, allerdings wäre es besser, alles, was IDisposable implementiert hat, in einem using-Block zu verwenden
Das stimmt so nicht.
In diesem Fall wäre das sogar ein Fehler, den auch FxCop anmäkeln würde und bei nicht ganz so sicheren Dispose-Implementierungen sogar eine Exception werfen kann.
Generell sollte man using() verwenden, ja - aber korrekt.
Bei Streams o.ä. erfolgt ein Disposing in der Regel "nach oben". Das heisst, dass der Dispose von BinaryReader intern auch den Dispose von FileStream ausführt.
Close wiederum tut nichts anderes - beim BinaryReader - als disposen.
"Vorbildlich" wäre hier also
var fileStream = ...
using(var binaryReader = new BinaryReader( fileStream, ....)
{
// ....
}
Weil das Dispose - hier - aber sehr defensiv entwickelt wurde wäre
using(var fileStream = ... )
using(var binaryReader = new BinaryReader( fileStream, ....)
{
// ....
}
auch kein Problem; kann dem ein oder anderen sogar besser gefallen; nur dem FxCop eben nicht.
Wenn also die data-Zuweisung im Code des Threaderstellers kein Fehler wirft ist der Code korrekt und auch "sicher".
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code