83 votes

En C#, pourquoi un objet List<string> ne peut-il pas être stocké dans une variable List<object> ?

Il semble qu'un objet Liste ne peut pas être stocké dans une variable Liste en C#, et ne peut même pas être explicitement coulé de cette façon.

List<string> sl = new List<string>();
List<object> ol;
ol = sl;

donne le résultat suivant : Cannot implicitly convert type System.Collections.Generic.List<string> a System.Collections.Generic.List<object>

Et puis...

List<string> sl = new List<string>();
List<object> ol;
ol = (List<object>)sl;

donne le résultat suivant : Cannot convert type System.Collections.Generic.List<string> a System.Collections.Generic.List<object>

Bien sûr, vous pouvez le faire en retirant tous les éléments de la liste de chaînes et en les remettant un par un, mais c'est une solution plutôt alambiquée.

38voto

Mike Stone Points 21293

Pensez-y de la manière suivante : si vous effectuez un tel transfert, puis ajoutez un objet de type Foo à la liste, la liste de chaînes de caractères n'est plus cohérente. Si vous deviez itérer la première référence, vous obtiendriez une exception de cast de classe parce qu'une fois que vous avez atteint l'instance de Foo, le Foo ne peut pas être converti en chaîne !

En passant, je pense qu'il serait plus important de savoir si vous pouvez ou non faire le moulage inversé :

List<object> ol = new List<object>();
List<string> sl;
sl = (List<string>)ol;

Je n'ai pas utilisé C# depuis un moment, donc je ne sais pas si c'est légal, mais ce genre de cast est en fait (potentiellement) utile. Dans ce cas, vous passez d'une classe plus générale (objet) à une classe plus spécifique (chaîne) qui s'étend à partir de la classe générale. De cette façon, si vous ajoutez à la liste des chaînes de caractères, vous ne violez pas la liste des objets.

Quelqu'un sait-il ou peut-il tester si un tel moulage est légal en C# ?

36voto

Ray Points 22127

Si vous utilisez .NET 3.5, jetez un coup d'œil à la méthode Enumerable.Cast. Il s'agit d'une méthode d'extension que vous pouvez appeler directement sur la liste.

List<string> sl = new List<string>();
IEnumerable<object> ol;
ol = sl.Cast<object>();

Ce n'est pas exactement ce que vous avez demandé mais ça devrait faire l'affaire.

Edit : Comme l'a noté Zooba, vous pouvez ensuite appeler ol.ToList() pour obtenir une liste.

14voto

Zooba Points 6440

Vous ne pouvez pas effectuer de cast entre des types génériques avec des paramètres de type différents. Les types génériques spécialisés ne font pas partie du même arbre d'héritage et sont donc des types non apparentés.

Pour faire cela, il faut utiliser la version pré-NET 3.5 :

List<string> sl = new List<string>();
// Add strings to sl

List<object> ol = new List<object>();

foreach(string s in sl)
{
    ol.Add((object)s);  // The cast is performed implicitly even if omitted
}

Utilisation de Linq :

var sl = new List<string>();
// Add strings to sl

var ol = new List<object>(sl.Cast<object>());

// OR
var ol = sl.Cast<object>().ToList();

// OR (note that the cast to object here is required)
var ol = sl.Select(s => (object)s).ToList();

11voto

Rex M Points 80372

La raison en est qu'une classe générique comme List<> est, dans la plupart des cas, traitée extérieurement comme une classe normale, par exemple lorsque vous dites List<string>() le compilateur dit ListString() (qui contient des chaînes de caractères). [Techniquement parlant, il s'agit d'une version extrêmement simplifiée en anglais de ce qui se passe].

Par conséquent, il est évident que le compilateur ne peut pas être assez intelligent pour convertir une ListString en ListObject en coulant les éléments de sa collection interne.

C'est pourquoi il existe des méthodes d'extension pour IEnumerable, comme Convert(), qui vous permettent de fournir facilement une conversion pour les éléments stockés dans une collection, ce qui peut être aussi simple que de passer d'un élément à un autre.

6voto

Jon Limjap Points 46429

Cela a beaucoup à voir avec la covariance, par exemple, les types génériques sont considérés comme des paramètres, et si les paramètres ne se résolvent pas correctement en un type plus spécifique, l'opération échoue. L'implication d'une telle situation est que vous ne pouvez pas vraiment faire un cast vers un type plus général comme l'objet. Et comme l'a dit Rex, l'objet List ne convertira pas chaque objet pour vous.

Vous pouvez essayer le code ff à la place :

List<string> sl = new List<string>();
//populate sl
List<object> ol = new List<object>(sl);

ou :

List<object> ol = new List<object>();
ol.AddRange(sl);

ol copiera (théoriquement) tout le contenu de sl sans problème.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X