2010-09-20 6 views
1

Je reçois un InvalidOperationException avec le message:l'invocation d'une méthode d'extension en utilisant la réflexion

« opérations liées en retard ne peuvent être effectuées sur les types ou les méthodes pour lesquelles ContainsGenericParameters est vrai. »

Ce qui suit est la partie pertinente du code:

// Gets the entity type of the table to update. 
Type entityType = Jobs.GetType(syncSettings.TableToUpdate); 

// Creates a generic list with the same type to hold the records to update. 
Type listType = typeof(List<>).MakeGenericType(entityType); 
object recordsToUpdate = Activator.CreateInstance(listType); 

// Fills the list recordsToUpdate... 
// A few lines below, I try to call the extension method ElementAt: 
MethodInfo elementAtMethod = typeof(Enumerable).GetMethod("ElementAt", BindingFlags.Static | BindingFlags.Public); 
elementAtMethod.MakeGenericMethod(entityType); 

object record = elementAtMethod.Invoke(
            recordsToUpdate, 
            new object[] { recordsToUpdate, recordIndex }); 

Dans ma dernière action, l'exception mentionnée ci-dessus est levée. Qu'est-ce que je fais mal? Que signifie cette erreur?

J'ai enquêté et il semble que le paramètre de type T soit encore générique. C'est pourquoi ContainsGenericParameters est vrai. Comment définir le paramètre sur entityType?

Répondre

2

Simplement, vous n'avez pas pris le résultat de MakeGenericMethod (il renvoie un différentMethodInfo représentant la fermée méthode)

elementAtMethod = elementAtMethod.MakeGenericMethod(entityType); 

Cependant, pourrais-je suggérer que, dans la plupart des cas, il est plus facile de utiliser le IList, non générique retombant à IEnumerable non générique (réflexion et génériques ne sont pas bons amis):

IList list = recordsToUpdate as IList; 
if(list != null) return list[recordIndex]; 
// fallback to IEnumerable 
if(recordIndex < 0) throw new IndexOutOfRangeException(); 
IEnumerable enumerable = (IEnumerable)recordsToUpdate; 
foreach (object item in enumerable) { 
    if (recordIndex-- == 0) return item; 
} 
throw new IndexOutOfRangeException(); 

(note, vous ne devrez pas utiliser le code de secours, puisque vous utilisez toujours List<T> qui implémente IList)

+0

Exactement! Cela prend tout son sens car la méthode MakeGenericMethod renvoie MethodInfo et non void. Merci @ Marc Gravell! –

+1

@Fabio - s'il vous plaît voir mon point sur 'IList'; l'approche reflexion/generique est ** beaucoup, beaucoup ** plus lente que le simple passage a 'IList' –

+0

Oui, je suis conscient que la réflexion est très lente, mais on m'a dit que ce n'était pas un problème puisque les méthodes que j'écris sont utilisé uniquement dans le rôle de travailleur. Le but de ce que je fais est qu'il devienne générique et continue de fonctionner, peu importe les changements, mais ce que vous avez dit me semble parfaitement logique et je vous en remercie. Je vais certainement le prendre en compte. Merci pour votre solution et votre meilleure alternative. Tu as sauvé ma journée! –

Questions connexes