API basate sulla reflection

In alcuni casi, l'uso della reflection nel codice non è scontato, quindi la catena di strumenti .NET Native non conserva i metadati necessari al runtime. In questo argomento vengono illustrati modelli di programmazione o API comuni non considerati parte dell'API di reflection ma basati sulla reflection per una corretta esecuzione. Se vengono usati nel codice sorgente, è possibile aggiungere informazioni su di essi al file di direttive di runtime (.rd.xml) in modo che le chiamate a queste API non generino un'eccezione MissingMetadataException o altre eccezioni al runtime.

Metodo Type.MakeGenericType

È possibile creare dinamicamente un'istanza di un tipo generico AppClass<T> chiamando il metodo Type.MakeGenericType usando un codice simile al seguente:

var t = Type.GetType("App1.AppClass`1", true);
Type[] typeArgs = {typeof(int)};
Type t2 = t.MakeGenericType(typeArgs);
Activator.CreateInstance(t2);

Per una corretta esecuzione del codice al runtime, sono necessari diversi elementi di metadati. Prima di tutto, sono richiesti metadati Browse per il tipo generico privo di istanze, AppClass<T>:

<Type Name="App1.AppClass`1" Browse="Required PublicAndInternal" />

Questo assicura l'esito positivo della chiamata al metodo Type.GetType(String, Boolean) e la restituzione di un oggetto Type valido.

Tuttavia, anche se si aggiungono i metadati per il tipo generico privo di istanze, la chiamata al metodo Type.MakeGenericType genera un'eccezione MissingMetadataException:

Questa operazione non può essere eseguita in quanto i metadati per il tipo seguente sono stati rimossi per motivi di prestazioni:

App1.AppClass`1<System.Int32>.

È possibile aggiungere la seguente direttiva di runtime al file di direttive di runtime per aggiungere i metadati Activate per la specifica creazione di un'istanza in AppClass<T> di System.Int32:

<TypeInstantiation Name="App1.AppClass" Arguments="System.Int32"
                   Activate="Required Public" />

Le singole creazioni di istanze in AppClass<T> richiedono direttive separate se vengono create con il metodo Type.MakeGenericType e non vengono usate staticamente.

Metodo MethodInfo.MakeGenericMethod

In una classe Class1 con un metodo generico GetMethod<T>(T t), GetMethod può essere richiamato mediante reflection usando un codice simile al seguente:

Type ct = typeof(Class1);
MethodInfo mi = ct.GetMethod("GetMethod");
Type[] typeArgs = {typeof(int)};
object[] parameters = { 12 };
var method = mi.MakeGenericMethod(typeArgs);
Class1 c = new Class1();
method.Invoke(c, parameters);

Per una corretta esecuzione, questo codice richiede diversi elementi di metadati:

  • I metadati Browse per il tipo di metodo da chiamare.

  • I metadati Browse per il metodo da chiamare. Se si tratta di un metodo pubblico, l'aggiunta di metadati Browse pubblici per il tipo contenitore include anche il metodo.

  • I metadati dinamici per il metodo da chiamare, in modo che il delegato di chiamata della reflection non venga rimosso dalla catena di strumenti .NET Native. Se i metadati dinamici non sono disponibili per il metodo, viene generata la seguente eccezione quando viene chiamato il metodo MethodInfo.MakeGenericMethod:

    MakeGenericMethod() cannot create this generic method instantiation because the instantiation was not metadata-enabled: 'App1.Class1.GenMethod<Int32>(Int32)'.
    

Le seguenti direttive di runtime assicurano la disponibilità di tutti i metadati necessari:

<Type Name="App1.Class1" Browse="Required PublicAndInternal">
   <MethodInstantiation Name="GenMethod" Arguments="System.Int32" Dynamic="Required"/>
</Type>

È necessaria una direttiva MethodInstantiation per ogni singola creazione di un'istanza del metodo richiamato dinamicamente; l'elemento Arguments viene aggiornato per riflettere ogni singolo argomento di creazione di un'istanza.

Metodi Array.CreateInstance e Type.MakeTypeArray

Il seguente esempio chiama i metodi Type.MakeArrayType e Array.CreateInstance in un tipo Class1.

Type t = typeof(Class1);
Type at = t.MakeArrayType(1);
Array arr = Array.CreateInstance(at, 10);

Se non sono presenti i metadati della matrice, si verificano i seguenti errori:

This operation cannot be carried out as metadata for the following type was removed for performance reasons:

App1.Class1[]

Unfortunately, no further information is available.

I metadati Browse per il tipo di matrice sono richiesti per la creazione dinamica di un'istanza. La seguente direttiva di runtime consente la creazione dinamica di un'istanza di Class1[].

<Type Name="App1.Class1[]" Browse="Required Public" />

Vedi anche