32 votes

Pourquoi le compilateur ne convertit-il pas var[] en object[] en c# ?

Il n'y a pas de différence entre ces deux lignes, car le compilateur, dans la deuxième ligne, comprend qu'il s'agit d'un tableau de type int .

var x = new int[] { 1, 2, 3 };   //Fine, x is int[]
var x = new [] { 1, 2, 3 };      //Fine, x is int[]

Mais pourquoi ne puis-je pas faire cela avec des types différents ? Pourquoi le compilateur ne convertit-il pas ma variable en type objet ?

var x = new object[] { 1, "df", 5 };   //Fine, x is object[]
var x = new [] { 1, "df", 5 };         //Error! "No best type found for implicity-typed-array"

EDIT :

Merci pour toutes vos réponses. Mais je me demande encore, quels sont les avantages et les inconvénients de faire en sorte que toutes les expressions que le compilateur ne peut pas convertir en type object ? (Parce que j'utilise var ce qui signifie qu'il ne peut être d'aucun type. Je comprends ainsi :) Pourquoi le compilateur ne trouve-t-il pas le type le plus proche des membres du tableau en remontant l'arbre d'héritage ?

38voto

Joey Points 148544

En new [] est une notation qui vous évite d'avoir à taper un type explicite des membres du tableau (ou qui vous permet de créer des tableaux dont les éléments ont un type anonyme), mais son inférence de type est limitée en ce sens que tous les éléments doivent partager le même type ou être implicitement convertibles en un type commun partagé par au moins un membre. Voir la spécification C#, section 7.6.10.4 :

Une expression de création de tableau de la troisième forme est appelée expression de création de tableau implicitement typée. Elle est similaire à la deuxième forme, sauf que le type de l'élément du tableau n'est pas explicitement donné, mais déterminé comme le meilleur type commun (§7.5.2.14) de l'ensemble des expressions dans l'initialisateur de tableau.

Voici des exemples d'expressions de création de tableau implicitement typées :

var a = new[] { 1, 10, 100, 1000 };                       // int[]
var b = new[] { 1, 1.5, 2, 2.5 };                         // double[]
var c = new[,] { { "hello", null }, { "world", "!" } };   // string[,]
var d = new[] { 1, "one", 2, "two" };                     // Error

La dernière expression provoque une erreur de compilation parce que ni l'un ni l'autre des deux int ni string est implicitement convertible en l'autre, et il n'y a donc pas de meilleur type commun. Une expression de création de tableau explicitement typée doit être utilisée dans ce cas, par exemple en spécifiant que le type est object[] . Il est également possible de convertir l'un des éléments en un type de base commun, qui deviendra alors le type d'élément déduit.

Le point clé ici est que le "meilleur type commun" ne peut être que l'un des types déjà présents. Comme Damien_Le_incrédule a souligné dans un commentaire : "Comme M. Lippert se plaît à le souligner autour de l'inférence, chaque fois qu'elle cherche le meilleur type commun, elle ne renvoie qu'un des types déjà présents - elle ne part pas à la chasse à l'ancêtre commun le plus dérivé." .

Ce n'est pas parce que chaque tableau peut être un object [] ne signifie pas qu'elle devrait. Du point de vue du compilateur, ce serait un choix trivial de dernier recours, mais un choix très contre-intuitif pour le développeur, je suppose.

18voto

Will Vousden Points 13332

Pour développer la réponse de Joey, prenez cet exemple :

interface IFoo { }
interface IBar { }

class A : IFoo, IBar { }
class B : IFoo, IBar { }

var array = new [] { new A(), new B() };

Les deux classes implémentent les deux interfaces (et dérivent aussi de object ), donc quel type doit être déduit pour array ?


Pour répondre à votre commentaire, considérons le cas où A y B ne partagent qu'une seule interface :

interface IFoo { }

class A : IFoo { }
class B : IFoo { }

var array = new [] { new A(), new B() };

Les deux sites A y B action object comme leur classe de base, mais il serait inutile de le déduire pour le type tableau. On s'attendrait à ce que ce soit IFoo si quoi que ce soit, donc cela violerait la le principe du moindre étonnement . Cependant, cela ne peut pas être fait de manière cohérente, comme je l'ai illustré.

Le comportement le plus sûr et le plus cohérent ici est simplement de ne pas autoriser l'inférence de type.

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