2010-12-08 59 views
5

Je crois qu'il est assez stupide, et je suis un peu gêné de poser ce genre de question, mais je ne pouvais toujours pas trouver la réponse:comment la liste <T> n'implémente pas Ajouter (valeur d'objet)?

Je regarde la classe List<T>, qui implemetns IList.

public class List<T> : IList 

l'une des méthodes incluses dans IList est

int Add(object value) 

Je comprends que List<T> ne devrait pas exposer cette méthode (sécurité de type ...), et il n'a pas vraiment. Mais comment peut-il être? classe mustnt mettre en œuvre l'ensemble de l'interface?

+0

Je ne suis pas sûr de ce que vous voulez dire en ne l'exposant pas, les interfaces ne peuvent avoir que des membres publics. –

+0

@Brad: 'List ' n'est pas une interface, et il dit que 'List ' ne devrait pas l'exposer. –

+0

Il est appelé "Implémentation d'interface explicite". – codymanix

Répondre

10

Je crois que cette méthode est implemented explicitly (interface):

public class List<T> : IList 
{ 
    int IList.Add(object value) {this.Add((T)value);} 
} 

Ce faisant, la méthode sera Add(object) par cachée. Vous ne pourrez l'appeler que si vous renvoyez l'instance List<T> à une instance IList.

+0

Vous avez raison à propos de la mise en œuvre explicite. Mais vous devriez corriger votre exemple ("récursion" et "ne peut pas compiler" continuer à apparaître dans mon esprit) ... :) – rsenna

+0

Vous auriez besoin de jeter la valeur à T pour que cela fonctionne. – Sean

2

List<T> implémente explicitement IList.Add(object value) ce qui explique pourquoi il n'est généralement pas visible. Vous pouvez tester en procédant comme suit:

IList list = new List<string>(); 
list.Add(new SqlDataReader()); // valid at compile time, will fail at runtime 
1

Elle implémente explicitement, de sorte que vous devez jeter à IList premiers à l'utiliser.

List<int> l = new List<int>(); 
IList il = (IList)l; 
il.Add(something); 
1

Vous pouvez appeler votre instance est prépondérante de la liste à l'interface première:

List<int> lst = new List<int>(); 
((IList)lst).Add("banana"); 

Et vous obtiendrez aussi agréable, l'exécution, ArgumentException.

2

Un voyage rapide à réflecteur montre que IList.Add est mis en œuvre comme ceci:

int IList.Add(object item) 
{ 
    ThrowHelper.IfNullAndNullsAreIllegalThenThrow<T>(item, ExceptionArgument.item); 
    try 
    { 
     this.Add((T) item); 
    } 
    catch (InvalidCastException) 
    { 
     ThrowHelper.ThrowWrongValueTypeArgumentException(item, typeof(T)); 
    } 
    return (this.Count - 1); 
} 

En d'autres termes, la mise en œuvre jette à T pour le faire fonctionner et il échoue vous passez un non T de type compatible.

+0

L'information est correcte, mais elle ne répond pas à la question. – Guffa

+0

Bien sûr que oui. IList.Add effectue un cast et appelle l'implémentation IList .Add. – Sean

1

Frederik is right que la mise en œuvre de List<T> de IList est explicite pour certains membres, en particulier ceux qui constituent une menace pour la sécurité de type.

L'implémentation qu'il suggère dans sa réponse ne peut pas être correcte, bien sûr, car elle ne compilerait pas.

Dans les cas de ce type, l'approche typique consiste à faire un vaillant effort vers , essayez pour que le membre de l'interface fonctionne, mais abandonnez si c'est impossible.

On notera que le procédé IList.Add est définie pour revenir:

La position dans laquelle le nouvel élément a été inséré, ou -1 pour indiquer que l'élément n'a pas été inséré dans la collection.

Donc, en fait, une mise en œuvre complète est possible:

int IList.Add(object value) 
{ 
    if (value is T) 
    { 
     Add((T)value); 
     return Count - 1; 
    } 

    return -1; 
} 

Ceci est juste une supposition, bien sûr. (Si vous voulez vraiment savoir à coup sûr, vous pouvez toujours utiliser Reflector.) Il peut être légèrement différent; par exemple, il pourrait lancer un NotSupportedException, ce qui est souvent fait pour des implémentations d'interface incomplètes telles que l'implémentation ReadOnlyCollection<T> de IList<T>. Mais puisque ce qui précède répond aux exigences documentées de IList.Add, je soupçonne qu'il est proche de la réalité.

+1

L'implémentation réelle (au moins dans .NET4) lève un 'ArgumentException' si vous essayez d'ajouter un élément du mauvais type. (Et, si je me souviens bien, il y avait un petit bogue avant .NET4 où essayer d'ajouter 'null' à un' List > 'via' IList.Add' lancerait aussi l'erreur de façon erronée.) – LukeH