Reflection-Only context

Ondřej Janáček       05.10.2014       Reflexe, .NET       9875 zobrazení

Když jsem nedávno psal aplikaci, která prochází hromadu assemblies a hledá v nich informace, automaticky jsem dal uživatelům k dispozici 32bitovou a 64bitovou verzi, protože jsem věděl, že nemůžu do jednoho procesu načíst assemblies postavené pro různé platformy. Tento článek popisuje techniku, která to za jistých okolností umožňuje a na kterou mě upozornil kolega.

Assembly.Load

V procesu načtení assembly do aplikační domény se bere ohled na několik věcí:

  1. Delay-signing
  2. CAS politika
  3. Platforma
  4. Možné spuštění kódu v assembly.
  5. Assembly binding

Věděl jsem, že u cílových souborů bude problém pouze platforma. Jak jej obejít?

Assembly.ReflectionOnlyLoad

Překvapilo mě, že jsem si této metody nevšiml dříve, v .NET je již od verze 2.0. Dále je tu metoda Assembly.ReflectionOnlyLoadFrom, která je vhodná, pokud známe cestu k assembly. ReflectionOnlyLoad je vhodná pro načítání z GAC. Oproti normálnímu načítání musíme ještě přidat extra kód pro donačtení závislostí. To je tu proto, abychom předešli načtení nechtěných závislostí (např. CLR dá přednost GAC verzím assemblies, které nemusíme chtít). Následuje kousek kódu pro načtení assembly včetně závislostí do AppDomain.

AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += 
    (s, a) => Assembly.ReflectionOnlyLoad(a.Name);
var assembly = Assembly.ReflectionOnlyLoadFrom("Sandbox.dll");

V prvním řádku se přihlásíme k odběru události, která se vyvolá vždy, když CLR najde chybějící závislost a vyřešíme ji načtením podle jména (měla by být v GAC nebo stejném adresáři jako je Sandbox.dll v tomto případě). Přesvědčit se o tom, jestli je assembly načtená v reflection-only kontextu můžeme pomocí assembly.ReflectionOnly property. Takto obejdeme všech 5 předchozích bodů ohledně pravidel načítání. Znamená to, že z načtené assembly nebude možné reflexí vytvořit žádnou instanci a provádět operace, které na pozadí nějaké instance vytvářejí. Mezi ně patří i dotazování na atributy. Pokud se to pokusíme udělat po starém, dostaneme InvalidOperationException.

CustomAttributeData

CustomAttributeData.GetCustomAttributes je metoda pro přístup k informacím o atributech definovaných jak na assembly, tak i na typech, metodách a vlastně všem ostatním v reflection-only kontextu. Ve srovnání s klasickým přístupem k vlastnostem atributů je struktura typu CustomAttributeDatatrochu těžkopádná. Pro čtení hodnot povinných parametrů je definována property ConstructorArguments a pro čtení nepovinných (auto-props a public fieldy) naopak NamedArguments. Obě tyto property jsou kolekce objektů typu CustomAttributeTypedArgument respektive CustomAttributeNamedArgument. V následujícím kousku kódu ukazuji přečtení hodnoty atributu. Je to pokračování předchozí ukázky.

// v assembly Sandbox.dll
[DebuggerDisplay("Text")]
public class Class1 {  }

// v jiné assembly
var type = assembly.GetType("Sandbox.Class1");
var attributes = CustomAttributeData.GetCustomAttributes(type);
Console.WriteLine(attributes[0].ConstructorArguments[0].Value);

Nejenže musíte vědět, jestli je cílová vlastnost povinný nebo nepovinný parametr, u nepovinných také musíte počítat s tím, že nejsou definovány, že jsou definovány na přeskáčku a také, že jsou definovány jako null (referenční typy), než se dotážete na jejich hodnotu. Tento přístup tedy znamená větší práci za cenu větší bezpečnosti a cenné schopnosti načíst do jedné AppDomain assemblies cílené pro různé platformy. Chování je jinak velmi podobné klasickému přístupu. Načtené assemblies musí být unikátní a po načtení zůstanou včetně závislostí v doméně až do jejího zániku.

 

hodnocení článku

0       Hodnotit mohou jen registrované uživatelé.

 

Nový příspěvek

 

Příspěvky zaslané pod tento článek se neobjeví hned, ale až po schválení administrátorem.

                       
Nadpis:
Antispam: Komu se občas házejí perly?
Příspěvek bude publikován pod identitou   anonym.

Nyní zakládáte pod článkem nové diskusní vlákno.
Pokud chcete reagovat na jiný příspěvek, klikněte na tlačítko "Odpovědět" u některého diskusního příspěvku.

Nyní odpovídáte na příspěvek pod článkem. Nebo chcete raději založit nové vlákno?

 

  • Administrátoři si vyhrazují právo komentáře upravovat či mazat bez udání důvodu.
    Mazány budou zejména komentáře obsahující vulgarity nebo porušující pravidla publikování.
  • Pokud nejste zaregistrováni, Vaše IP adresa bude zveřejněna. Pokud s tímto nesouhlasíte, příspěvek neodesílejte.

Příspěvky zaslané pod tento článek se neobjeví hned, ale až po schválení administrátorem.

přihlásit pomocí externího účtu

přihlásit pomocí jména a hesla

Uživatel:
Heslo:

zapomenuté heslo

 

založit nový uživatelský účet

zaregistrujte se

 
zavřít

Nahlásit spam

Opravdu chcete tento příspěvek nahlásit pro porušování pravidel fóra?

Nahlásit Zrušit

Chyba

zavřít

feedback