Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Anmärkning
Den här artikeln är specifik för .NET Framework. Det gäller inte för nyare implementeringar av .NET, inklusive .NET 6 och senare versioner.
I den här artikeln beskrivs olika sätt att undvika problem av typen identitet som kan leda till InvalidCastException, MissingMethodExceptionoch andra fel. I artikeln beskrivs följande rekommendationer:
Den första rekommendationen, förstå fördelarna och nackdelarna med belastningskontexter, ger bakgrundsinformation för de andra rekommendationerna, eftersom alla är beroende av kunskap om belastningskontexter.
Förstå fördelarna och nackdelarna med belastningskontexter
I en programdomän kan sammansättningar läsas in i någon av tre kontexter, eller läsas in utan kontext:
Standardladdningskontexten innehåller sammansättningar som hittas genom att avsöka den globala sammansättningscachen, värdsammansättningsarkivet om körningen är hostad (till exempel i SQL Server) och i programdomänens ApplicationBase och PrivateBinPath. De flesta överlagringar av Load metoden läser in sammansättningar i den här kontexten.
Inläsningskontexten innehåller sammansättningar som läses in från platser som inte genomsöks av inläsaren. Till exempel kan tillägg installeras i en katalog som inte finns under programsökvägen. Assembly.LoadFrom, AppDomain.CreateInstanceFrom, och AppDomain.ExecuteAssembly är exempel på metoder som läses in via sökväg.
Reflektionskontexten innehåller sammanställningar som läses in med ReflectionOnlyLoad och ReflectionOnlyLoadFrom metoderna. Det går inte att köra kod i den här kontexten, så den beskrivs inte här. Mer information finns i How to: Load Assemblies into the Reflection-Only Context (Läs in sammansättningar i Reflection-Only Context).
Om du genererade en tillfällig dynamisk samling genom att använda reflection emit finns samlingen inte i något sammanhang. Dessutom läses de flesta sammansättningar som läses in med hjälp LoadFile av metoden in utan kontext, och sammansättningar som läses in från bytematriser läses in utan kontext om inte deras identitet (efter att principen har tillämpats) anger att de finns i den globala sammansättningscachen.
Körningskontexterna har fördelar och nackdelar, vilket diskuteras i de följande avsnitten.
Standardinläsningskontext
När sammansättningar läses in i standardinläsningskontexten läses deras beroenden in automatiskt. Beroenden som läses in i standardinläsningskontexten hittas automatiskt för sammansättningar i standardinläsningskontexten eller inläsningskontexten. Inläsning efter sammansättningsidentitet ökar stabiliteten för program genom att se till att okända versioner av sammansättningar inte används (se avsnittet Undvik bindning på partiella sammansättningsnamn ).
Användning av standardinläsningskontexten har följande nackdelar:
Beroenden som läses in i andra kontexter är inte tillgängliga.
Du kan inte läsa in sammansättningar från platser utanför sökvägen för avsökning till standardinläsningskontexten.
Load-From kontext
Med inläsningskontexten kan du läsa in en sammansättning från en sökväg som inte finns under programsökvägen och därför inte ingår i avsökningen. Det gör att beroenden kan lokaliseras och läsas in från den sökvägen, eftersom sökvägsinformationen underhålls av kontexten. Dessutom kan sammansättningar i den här kontexten använda beroenden som läses in i standardinläsningskontexten.
Att läsa in sammansättningar med hjälp Assembly.LoadFrom av metoden, eller någon av de andra metoderna som läser in efter sökväg, har följande nackdelar:
Om en sammansättning med samma identitet redan har lästs in i inläsningskontexten LoadFrom returnerar den inlästa sammansättningen även om en annan sökväg har angetts.
Om en sammansättning läses in med LoadFrom, och senare en sammansättning i standardinläsningskontexten försöker läsa in samma sammansättning med visningsnamn, misslyckas belastningsförsöket. Detta kan inträffa när en sammansättning deserialiseras.
Om en sammansättning läses in med LoadFrom, och sökvägen för avsökning innehåller en sammansättning med samma identitet, men på en annan plats, kan ett InvalidCastException, MissingMethodExceptioneller annat oväntat beteende inträffa.
LoadFrom ställer krav på FileIOPermissionAccess.Read och FileIOPermissionAccess.PathDiscovery, eller WebPermission, på den angivna sökvägen.
Om det finns en förkompilerad avbildning för samlingen används den inte.
Sammansättningen kan inte läsas in som domänneutral.
I .NET Framework-versionerna 1.0 och 1.1 tillämpas inte principen.
Ingen kontext
Inläsning utan kontext är det enda alternativet för övergående sammansättningar som genereras med reflection emit. Inläsning utan kontext är det enda sättet att läsa in flera sammansättningar som har samma identitet i en programdomän. Kostnaden för avsökning undviks.
Sammansättningar som läses in från bytematriser läses in utan kontext om inte sammansättningens identitet, som upprättas när principen tillämpas, matchar identiteten för en sammansättning i den globala sammansättningscachen. I så fall läses sammansättningen in från den globala sammansättningscacheminnet.
Inläsning av sammansättningar utan kontext har följande nackdelar:
Andra sammansättningar kan inte binda till sammansättningar som läses in utan kontext, såvida du inte hanterar händelsen AppDomain.AssemblyResolve .
Beroenden läses inte in automatiskt. Du kan förläsa in dem utan kontext, förläsa in dem i den förvalda inläsningskontexten eller ladda in dem genom att hantera AppDomain.AssemblyResolve-händelsen.
Om du läser in flera sammansättningar med samma identitet utan kontext kan det orsaka typidentitetsproblem som liknar dem som orsakas av inläsning av sammansättningar med samma identitet i flera kontexter. Se Undvik att läsa in en sammansättning i flera kontexter.
Om det finns en förkompilerad avbildning för samlingen används den inte.
Sammansättningen kan inte läsas in som domänneutral.
I .NET Framework-versionerna 1.0 och 1.1 tillämpas inte principen.
Undvik bindning för partiella sammansättningsnamn
Partiell namnbindning inträffar när du endast anger en del av sammansättningsvisningsnamnet (FullName) när du läser in en sammansättning. Du kan till exempel anropa Assembly.Load metoden med endast det enkla namnet på sammansättningen och utelämna version, kultur och offentlig nyckeltoken. Eller så kan du anropa Assembly.LoadWithPartialName metoden, som först anropar Assembly.Load metoden och, om det inte går att hitta sammansättningen, söker i den globala sammansättningscacheminnet och läser in den senaste tillgängliga versionen av sammansättningen.
Partiell namnbindning kan orsaka många problem, inklusive följande:
Metoden Assembly.LoadWithPartialName kan läsa in en annan sammansättning med samma enkla namn. Två program kan till exempel installera två helt olika sammansättningar som båda har det enkla namnet
GraphicsLibraryi den globala sammansättningscachen.Sammansättningen som faktiskt läses in kanske inte är bakåtkompatibel. Om du till exempel inte anger versionen kan det leda till att en mycket senare version läses in än den version som programmet ursprungligen skrevs att använda. Ändringar i den senare versionen kan orsaka fel i ditt program.
Den sammansättning som faktiskt laddas kanske inte är framåtinriktat kompatibel. Du kan till exempel ha skapat och testat ditt program med den senaste versionen av en sammansättning, men partiell bindning kan läsa in en mycket tidigare version som saknar funktioner som programmet använder.
Installation av nya program kan bryta befintliga program. Ett program som använder LoadWithPartialName metoden kan brytas genom att installera en nyare, inkompatibel version av en delad sammansättning.
Oväntad laddning av beroenden kan inträffa. Om du läser in två sammansättningar som delar ett beroende kan inläsning av dem med partiell bindning resultera i en sammansättning med hjälp av en komponent som den inte har skapats eller testats med.
På grund av de problem som den kan orsaka LoadWithPartialName har metoden markerats som föråldrad. Vi rekommenderar att du använder Assembly.Load metoden i stället och anger fullständiga visningsnamn för sammansättning. Titta på Förstå fördelarna och nackdelarna med laddningskontexter och överväg att byta till standardladdningskontexten.
Om du vill använda LoadWithPartialName metoden eftersom den gör laddning av sammansättningar enkel, bör du tänka på att om programmet misslyckas med ett felmeddelande som identifierar den saknade sammansättning kan det ge en bättre användarupplevelse än att automatiskt använda en okänd version av sammansättningarna, vilket kan orsaka oförutsägbart beteende och säkerhetsbrister.
Undvik att läsa in en sammansättning i flera kontexter
Att läsa in en assembly i flera kontexter kan orsaka problem med typidentitet. Om samma typ läses in från samma sammansättning i två olika kontexter är det som om två olika typer med samma namn hade lästs in. En InvalidCastException utlöses om du försöker att konvertera från en typ till en annan, med det förvirrande meddelandet att typen MyType inte kan omvandlas till typ MyType.
Anta till exempel att ICommunicate gränssnittet deklareras i en sammansättning med namnet Utility, som refereras av ditt program och även av andra sammansättningar som programmet läser in. Dessa andra sammansättningar innehåller typer som implementerar ICommunicate gränssnittet så att programmet kan använda dem.
Tänk nu på vad som händer när programmet körs. Sammansättningar som refereras av ditt program läses in i standardinläsningskontexten. Om du läser in en målsammansättning med dess identitet genom att använda metoden Load, kommer den att vara i standardinläsningskontexten, liksom dess beroenden. Både programmet och målsammansättningen använder samma Utility sammansättning.
Tänk dock att du läser in målsammansättningen med dess filsökväg med hjälp av LoadFile metoden. Sammansättningen läses in utan någon kontext, så dess beroenden läses inte in automatiskt. Du kan ha en hanterare för händelsen AppDomain.AssemblyResolve att ange beroendet, och den kan ladda Utility-samlingen utan kontext med hjälp av LoadFile-metoden. Nu när du skapar en instans av en typ som finns i målsammansättningen och försöker tilldela den till en variabel av typen ICommunicate, genereras en InvalidCastException eftersom körningen anser att gränssnitten ICommunicate i de två kopiorna av Utility sammansättningen är olika typer.
Det finns många andra scenarier där en sammansättning kan läsas in i flera kontexter. Den bästa metoden är att undvika konflikter genom att flytta målfilen till programvägens sökväg och använda Load-metoden med det fullständiga visningsnamnet. Sammansättningen läses sedan in i standardinläsningskontexten och båda sammansättningarna använder samma Utility sammansättning.
Om målsamlingen måste ligga utanför programsökvägen kan du använda LoadFrom metoden för att läsa in i load-from kontexten. Om målförsamlingen kompilerades med en referens till programmets Utility komponent, kommer den att använda den Utility komponent som programmet har laddat in i standardladdningskontexten. Observera att problem kan uppstå om målsammansättningen har ett beroende av en kopia av Utility sammansättningen som finns utanför programsökvägen. Om sammansättningen laddas i load-from kontexten innan programmet laddar Utility-sammansättningen, kommer inläsningen av ditt program att misslyckas.
I sektionen som behandlar att växla till standardinläsningskontexten diskuteras alternativ till filsökvägsinläsningar som LoadFile och LoadFrom.
Undvik att läsa in flera versioner av en sammansättning i samma kontext
Att läsa in flera versioner av en sammansättning i en belastningskontext kan orsaka typidentitetsproblem. Om samma typ läses in från två versioner av samma sammansättning är det som om två olika typer med samma namn hade lästs in. En InvalidCastException utlöses om du försöker att konvertera från en typ till en annan, med det förvirrande meddelandet att typen MyType inte kan omvandlas till typ MyType.
Programmet kan till exempel läsa in en version av Utility sammansättningen direkt och senare kan den läsa in en annan sammansättning som läser in en annan version av Utility sammansättningen. Eller så kan ett kodfel orsaka att två olika kodsökvägar i programmet läser in olika versioner av en sammansättning.
I standardinläsningskontexten kan det här problemet uppstå när du använder Assembly.Load metoden och ange fullständiga visningsnamn för sammansättning som innehåller olika versionsnummer. För sammansättningar som läses in utan kontext kan problemet orsakas av Assembly.LoadFile metoden för att läsa in samma sammansättning från olika sökvägar. Körmiljön anser att två assemblys som läses in från olika sökvägar är olika assemblys, även om deras identiteter är desamma.
Förutom typidentitetsproblem kan flera versioner av en sammansättning orsaka en MissingMethodException om en typ som läses in från en version av sammansättningen skickas till kod som förväntar sig den typen från en annan version. Koden kan till exempel förvänta sig en metod som har lagts till i den senare versionen.
Mer subtila fel kan inträffa om beteendet för typen ändras mellan versioner. En metod kan till exempel utlösa ett oväntat undantag eller returnera ett oväntat värde.
Granska koden noggrant för att se till att endast en version av en sammansättning läses in. Du kan använda AppDomain.GetAssemblies metoden för att avgöra vilka sammansättningar som läses in vid en viss tidpunkt.
Överväg att ändra till den förinställda inläsningskontexten
Granska programmets mönster för sammansättningsinläsning och distribution. Kan du eliminera sammansättningar som läses in från bytematriser? Kan du flytta sammansättningar till sökvägen för avsökning? Om sammansättningar finns i den globala sammansättningscacheminnet eller i programdomänens avsökningssökväg (dvs. dess ApplicationBase och PrivateBinPath), kan du läsa in sammansättningen med dess identitet.
Om det inte går att placera alla assemblies i avsökningsvägen kan du överväga alternativ som att använda .NET Framework-tilläggsmodellen, placera assemblies i den globala assembly-cachen eller skapa applikationsdomäner.
Överväg att använda .NET Framework Add-In-modellen
Om du använder inläsningskontexten för att implementera tillägg, som vanligtvis inte är installerade i programbasen, använder du .NET Framework-tilläggsmodellen. Den här modellen tillhandahåller isolering på programdomän eller processnivå, utan att du behöver hantera programdomäner själv. Information om tilläggsmodellen finns i Tillägg och Utökningsbarhet.
Överväg att använda den globala assembly-cachen
Placera sammansättningar i den globala sammansättningscachen för att dra nytta av en delad sammansättningssökväg som ligger utanför programbasen, utan att förlora standardinläsningskontextens fördelar eller drabbas av nackdelarna med de andra kontexterna.
Överväg att använda programdomäner
Om du bedömer att vissa av dina sammansättningar inte kan distribueras i programmets avsökningssökväg kan du överväga att skapa en ny programdomän för dessa sammansättningar. Använd en AppDomainSetup för att skapa den nya programdomänen och använd AppDomainSetup.ApplicationBase egenskapen för att ange sökvägen som innehåller de sammansättningar som du vill läsa in. Om du har flera kataloger att avsöka kan du ange ApplicationBase till en rotkatalog och använda AppDomainSetup.PrivateBinPath egenskapen för att identifiera de underkataloger som ska avsökas. Du kan också skapa flera programdomäner och ange ApplicationBase för varje programdomän till rätt sökväg för dess sammansättningar.
Observera att du kan använda Assembly.LoadFrom metoden för att läsa in dessa sammansättningar. Eftersom de nu är i avsökningssökvägen läses de in i standardinläsningskontexten i stället för inläsningskontexten. Vi rekommenderar dock att du växlar till Assembly.Load metoden och anger fullständiga visningsnamn för sammansättning för att säkerställa att rätt versioner alltid används.