Unterschied zwischen LoadFile und LoadFrom mit .NET-Assemblys?


126

Ich habe mir die MSDN-Dokumentation angesehen und bin immer noch ein wenig verwirrt darüber, was genau der Unterschied zwischen der Verwendung LoadFileund LoadFromdem Laden einer Baugruppe ist. Kann jemand ein Beispiel oder eine Analogie liefern, um es besser zu beschreiben? Die MSDN-Dokumentation hat mich mehr verwirrt. Ist auch ReflectionOnlyLoadFromdasselbe wie mit der LoadFromAusnahme, dass die Baugruppe nur im Reflexionsmodus geladen wird.

Da meine .NET-Erfahrung nicht die größte ist, sind hier einige Fragen zur MSDN-Dokumentation mit LoadFile:

1) Was bedeutet es, LoadFileBaugruppen zu untersuchen, die dieselbe Identität haben, sich aber auf unterschiedlichen Pfaden befinden? Was ist die Identität (Beispiel)?

2) Es gibt an, LoadFiledass keine Dateien in den 'LoadFrom-Kontext' geladen werden und Abhängigkeiten nicht über den Ladepfad aufgelöst werden. Was bedeutet das, kann jemand ein Beispiel geben?

3) Schließlich wird angegeben, dass LoadFiledies in diesem eingeschränkten Szenario nützlich ist, da LoadFrom keine Assemblys laden kann, die dieselben Identitäten, aber unterschiedliche Pfade haben. Es wird nur die erste derartige Assembly geladen, was mich erneut zu der gleichen Frage bringt: Was ist die Identität der Assemblys?


10
Im Ernst, ich denke auch manchmal, dass MS bessere Autoren oder etwas anderes einstellen sollte, da die Sätze nicht immer verständlich sind ...
Tarik


1
@ColonelPanic MS kann sagen, dass alles dokumentiert ist ... aber mit einem Hilfefaktor von nulloooo.
Legenden

Antworten:


96

Klärt das auf?

// path1 and path2 point to different copies of the same assembly on disk:

Assembly assembly1 = Assembly.LoadFrom(path1);
Assembly assembly2 = Assembly.LoadFrom(path2);

// These both point to the assembly from path1, so this is true
Console.WriteLine(assembly1.CodeBase == assembly2.CodeBase);

assembly1 = Assembly.LoadFile(path1);
assembly2 = Assembly.LoadFile(path2);

// These point to different assemblies now, so this is false
Console.WriteLine(assembly1.CodeBase == assembly2.CodeBase);

Bearbeiten : Um die Fragen zu beantworten, die Sie in Ihrer überarbeiteten Frage aufgeworfen haben, möchten Sie auf jeden Fall Suzanne Cook über die Identität der Versammlung lesen .

Es gibt viele Regeln, die regeln, wie Assemblys geladen werden, und einige davon haben damit zu tun, wie sie Abhängigkeiten auflösen. Wenn Ihre AssemblyA von AssemblyB abhängig ist, wo sollte .NET nach AssemblyB suchen? Im Global Assembly Cache das gleiche Verzeichnis, in dem AssemblyA gefunden wurde, oder irgendwo anders? Wenn mehrere Kopien dieser Baugruppe gefunden werden, wie sollte sie dann auswählen, welche verwendet werden soll?

LoadFromhat einen Satz von Regeln, während LoadFilehat einen anderen Satz von Regeln. Es ist schwer vorstellbar, warum viele Gründe verwendet werden LoadFilemüssen. Wenn Sie jedoch verschiedene Kopien derselben Baugruppe reflektieren müssen, ist dies für Sie da.


2
Ist die CodeBase mit der Identität identisch?
Xaisoft

Nein, ich habe hier nur CodeBase als willkürliche Eigenschaft der Assembly verwendet, um zu veranschaulichen, dass die zweite Assembly-Instanz auf die 'falsche' Datei zeigte (im ersten Beispiel). Ich aktualisiere meine Antwort mit weiteren Details.
Jeff Sternal

1
Es klärt es ein wenig auf, aber wie zeigen Pfad1 und Pfad2 auf verschiedene Kopien derselben Assembly auf der Festplatte, wenn LoadFrom verwendet wird und wenn LoadFile verwendet wird, zeigen Pfad1 und Pfad2 auf verschiedene Assemblys. Was ist ein Beispiel für Pfad1 und Pfad2? Danke für Ihre Geduld.
Xaisoft

Warum überprüfen Sie zwei Zeichenfolgenreferenzen auf Wertgleichheit mit string.Compare(x, y) == 0? Ich denke du willst x == yda? Wenn Sie aus unklaren Gründen eine kulturabhängige Gleichstellungsprüfung wünschen, ist es beispielsweise klarer zu schreiben string.Equals(x, y, StringComparison.CurrentCulture).
Jeppe Stig Nielsen

@ JeffSternal Link auf "Suzanne Cook auf Assembly Identity" scheint hier gebrochen zu sein ...
Martin Verjans

61

Aus dem Blog von Suzanne Cook :

LoadFile vs. LoadFrom

Seien Sie vorsichtig - das ist nicht dasselbe.

LoadFrom () durchläuft Fusion und kann auf einem anderen Pfad, jedoch mit derselben Identität, zu einer anderen Assembly umgeleitet werden, wenn eine bereits im LoadFrom-Kontext geladen ist.

LoadFile () bindet überhaupt nicht über Fusion - der Loader fährt einfach fort und lädt genau *, was der Aufrufer angefordert hat. Es wird weder der Load- noch der LoadFrom-Kontext verwendet.

LoadFrom () gibt Ihnen normalerweise das, wonach Sie gefragt haben, aber nicht unbedingt. LoadFile () ist für diejenigen, die wirklich genau das wollen, was angefordert wird. (* Ab Version 2 wird die Richtlinie jedoch sowohl auf LoadFrom () als auch auf LoadFile () angewendet, sodass LoadFile () nicht unbedingt genau das ist, was angefordert wurde. Ab Version 2 auch, wenn sich eine Assembly mit ihrer Identität in befindet Im GAC wird stattdessen die GAC-Kopie verwendet. Verwenden Sie ReflectionOnlyLoadFrom (), um genau das zu laden, was Sie möchten. Beachten Sie jedoch, dass auf diese Weise geladene Assemblys nicht ausgeführt werden können.)

LoadFile () hat einen Haken. Da kein Bindungskontext verwendet wird, werden seine Abhängigkeiten nicht automatisch in seinem Verzeichnis gefunden. Wenn sie im Ladekontext nicht verfügbar sind, müssen Sie das AssemblyResolve-Ereignis abonnieren, um eine Bindung an sie herzustellen.

Siehe hier .

Siehe auch Auswählen eines verbindlichen Kontextartikels im selben Blog.


Danke, ich werde den Blog lesen, ich habe meinen Beitrag mit einigen Fragen bezüglich der MSDN-Dokumentation aktualisiert.
Xaisoft

@Xaisoft - Suzanne Cooks Blog kommt erneut mit der Antwort einer Assemblies-Identität zur Rettung. Siehe blogs.msdn.com/suzcook/archive/2003/07/21/57232.aspx . Es handelt sich im Wesentlichen um einen "Anzeigenamen der Baugruppe" und dies ist ungefähr so: "System, Version = 1.0.3300.0, Kultur = neutral, PublicKeyToken = b77a5c561934e089" enthält also sowohl den tatsächlichen Namen der Baugruppe als auch die Versionsnummer sowie andere identifizierende Informationen (z PublicKeyToken etc.).
CraigTP

1
Worauf bezieht sie sich, wenn sie über Fusion spricht?
Xaisoft

1
In der Tat ist Jeff genau richtig. Unter diesem Link: grimes.demon.co.uk/workshops/fusionWS.htm finden Sie ein nettes Tutorial zum Fusion-Subsystem und seiner Technologie zum Laden von Baugruppen in .NET
CraigTP

1
Beachten Sie, dass die oben angegebene URL (grimes.demon.co.uk/workshops/fusionWS.htm) nicht mehr gültig ist und jetzt zu: richardgrimes.com/workshops/fusionWS.htm
CraigTP

45

Nach vielem Kopfkratzen habe ich heute Nachmittag selbst einen Unterschied entdeckt.

Ich wollte zur Laufzeit eine DLL laden, und die DLL befand sich in einem anderen Verzeichnis. Diese DLL hatte ihre eigenen Abhängigkeiten (DLLs), die sich ebenfalls in demselben Verzeichnis befanden.

LoadFile (): Die spezifische DLL wurde geladen, nicht jedoch die Abhängigkeiten. Als der erste Aufruf innerhalb der DLL an eine dieser anderen DLLs erfolgte, wurde eine FileNotFoundException ausgelöst.

LoadFrom (): Lud die von mir angegebene DLL sowie alle Abhängigkeiten, die in diesem Verzeichnis lebten.


4
Das war genau mein Problem! Ich habe das FileNotFoundExceptionbeim Erstellen einer neuen Instanz eines Objekts erhalten, das in einer Assembly definiert ist, auf die von der Assembly verwiesen wird, mit der ich gerade geladen habe .LoadFile. Das .LoadFromzu ändern schien das Problem zu beheben, aber ich wusste nicht warum! Vielen Dank
Connell

1
Danke, ich hatte das gleiche Problem.
Ivandro IG Jao

4

Hinweis: Wenn eine Assembly über einen 8.3-Pfad und dann über einen Nicht-8.3-Pfad geladen wird, werden sie als unterschiedliche Assemblys angezeigt, obwohl es sich um dieselbe physische DLL handelt.



0

Ein Unterschied, den ich bemerkt habe, ist:

Assembly.LoadFile - Lädt Assemblys in verschiedenen AppDomains mit eingeschränkten Benutzerrechten (Differenzprinzip). Operationen wie Serilisierung / Deserilisierung konnten nicht durchgeführt werden.

Assembly.LoadFrom - Lädt die Assembly in dieselbe AppDomain mit denselben Benutzerrechten (dasselbe Prinzip).


3
Das ist nicht richtig. Was lässt Sie glauben, dass Assembly.LoadFile eine Assembly in eine andere AppDomain lädt?
fr34kyn01535

0

In meinem Fall musste ich nur den ASP-Anwendungscache @ löschen C:\Windows\Microsoft.NET\Framework\[asp version]\Temporary ASP.NET Files. Es wird neu erstellt, wenn die Site zum ersten Mal ausgeführt wird. Stellen Sie sicher, dass Sie IIS zuerst stoppen.

Hoffe das hilft jemandem wie es für mich getan hat.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.