Vous ne pouvez pas utiliser un tableau «en ligne» en C #?

89

Imagine que tu as ça quelque part

public static T AnyOne<T>(this T[] ra) where T:class
    {
    int k = ra.Length;
    int r = Random.Range(0,k);
    return ra[r];
    }

ou même juste ça

public static string OneOf(this string[] strings)
    {
    return "a";
    }

Alors, bien sûr, vous pouvez le faire ...

string[] st = {"a","b","c"};
string letter = st.AnyOne();

... qui est genial. MAIS. Il semblerait que vous ne puissiez PAS faire cela:

string letter = {"a","b","c"}.AnyOne();

ou bien peut-être ceci

string letter = ( {"a","b","c"} ).AnyOne();

ou quoi que ce soit d'autre que j'ai essayé.

En fait (1) pourquoi ne peut-on pas faire cela? et (2) est-ce que je manque quelque chose, comment feriez-vous cela s'il y a un moyen?

Fattie
la source
5
Je ne suis pas sûr que la question en double soit appropriée, l'OP ne pose pas de question sur les initialiseurs de tableau, mais pourquoi le compilateur ne reconnaîtra pas l'objet en tant que tableau tant qu'il ne sera pas affecté.
Ron Beyer
4
Je ne suis pas familier avec la terminologie C #, mais je crois que cela est plus communément appelé un littéral ou un littéral de tableau plutôt qu'un inline .
chi
3
Cet élément syntaxique est un initialiseur de tableau ou un initialiseur de collection , selon le contexte dans lequel il est utilisé. Dans aucun des cas, il n'est classé comme une expression .
Eric Lippert

Réponses:

129

Vous devez d'abord créer le tableau, en utilisant new[].

string letter = (new[] {"a","b","c"}).AnyOne();

Comme @hvd l'a mentionné, vous pouvez le faire sans paranthèses (..), j'ai ajouté les paranthèses car je pense que c'est plus lisible.

string letter = new[] {"a","b","c"}.AnyOne();

Et vous pouvez spécifier le type de données new string[]comme sur d'autres réponses a été mentionné.


Vous ne pouvez pas simplement le faire {"a","b","c"}, car vous pouvez le considérer comme un moyen de peupler le tableau, pas de le créer.

Une autre raison sera que le compilateur sera confus, ne saura pas quoi créer, par exemple, a string[]{ .. }ou a List<string>{ .. }.

En utilisant uniquement le new[]compilateur, vous pouvez savoir par type de données ( ".."), entre {..}, ce que vous voulez ( string). La partie essentielle est []que vous voulez un tableau.

Vous ne pouvez même pas créer un tableau vide avec new[].

string[] array = new []{ }; // Error: No best type found for implicity-typed array
adricadar
la source
13
Vous n'avez pas besoin de ces parenthèses. string letter = new[] {"a","b","c"}.AnyOne();est très bien. Si vous les voulez, si vous pensez que c'est plus lisible avec les parenthèses, elles sont valides, mais dans ce cas, je pense qu'il vaut au moins la peine de mentionner que c'est un choix conscient de votre part, qu'il n'a pas été forcé par la langue.
Je connais la syntaxe new [] {1,2}, mais y a-t-il une syntaxe encore plus simple? Quelque chose comme [1, 2]?
seguso
51

(1) pourquoi ne peut-on pas faire cela? {"a","b","c"}.AnyOne();

Cette ligne:

string[] st = {"a","b","c"};

est un raccourci pour une expression de création de tableau équivalente (sous ILSpy )

string[] st = new string[]  {"a","b","c"};

Cela string[] st = {"a","b","c"} ne peut être utilisé qu'au moment de la déclaration , vous ne pouvez pas ne pas l'utiliser ailleurs, vous ne pouvez même pas faire:

string[] st;
st = {"a", "b", "c"}; //Error

Il est expliqué dans la section 7.6.10.4 pour l'expression Array Creation dans les spécifications du langage C #.

Donc cela "{"a", "b", "c"}"seul sans utilisation dans la déclaration ne signifie rien. Par conséquent, vous ne pouvez pas l'utiliser avec votre méthode d'extension, car votre méthode d'extension fonctionne sur un tableau.

(2) est-ce que je manque quelque chose, comment feriez-vous cela s'il y a un moyen?

Déjà mentionné dans la réponse de @ adricadar , vous pouvez faire:

(new[] {"a","b","c"}).AnyOne();

ou

(new string[] {"a","b","c"}).AnyOne();
Habib
la source
48

Je repousse les questions "pourquoi pas" car d'abord, les réponses ne sont presque jamais satisfaisantes - vous avez déjà obtenu la réponse "la fonctionnalité n'est pas comme vous le souhaitez car la spécification ne dit pas ce que vous voulez qu'elle dise" , ce qui, je suppose, n'était pas une réponse particulièrement satisfaisante. Deuxièmement, l'équipe de conception n'a pas à justifier pourquoi le monde n'est pas comme vous le souhaitez; les fonctionnalités n'existent pas gratuitement et sont ensuite conçues hors du langage; au contraire, les fonctionnalités doivent d'abord être justifiées, puis conçues dans.

Alors essayons de rendre votre question «pourquoi pas» un peu plus claire. La caractéristique existante est "un initialiseur de tableau peut être utilisé (a) sur le côté droit des égaux dans une initialisation ou (b) à droite d'une construction d'objet de type tableau". La fonctionnalité proposée est: "un initialiseur de tableau peut également être utilisé comme expression". La question est "quelles critiques Eric ferait-il du long métrage proposé?"

La première critique que je ferais est que le type d’expression n’est pas clair. Dans un initialiseur de variable, vous avez le type de la variable et dans une expression de création d'objet, vous avez le type de l'objet; à partir des deux, nous pouvons déduire le type du tableau construit. Sans aucun indice, quel type devrions-nous en déduire?

Dans C # 1.0, lorsque cette fonctionnalité a été ajoutée, il y avait un grand total de zéro inférences de type effectuées dans le langage. Un principe de conception dans les premiers jours de C # était "pas de surprises", et que le compilateur n'était pas "trop ​​intelligent". Si le développeur souhaite qu'une expression soit d'un type particulier, ce type doit être d'une certaine manière évident dans l'expression. Quand tu dis

new double[] { 1, 2, 3.4 }

il est assez clair quel type est prévu. De même

new Animal[] { cat, dog, null }

La fonctionnalité proposée viole ce principe. L'expression doit avoir un type, mais le type de l'argument est loin d'être clair

M({cat, dog, null})

De plus: Supposons que nous ayons deux surcharges de M, dont l'une prend un tableau de Animalet l'autre qui prend un tableau de IPet. Quelle surcharge de Mest applicable? L'une des conversions est-elle meilleure que l'autre? Les types d'éléments sont Catet Dog; est-il logique de déduire un type qui n'y figure même pas? Ce sont toutes des questions qui doivent être examinées par l'équipe de conception, et ce sont des questions qui n'ont en aucun cas des réponses évidentes. La fonctionnalité proposée nous conduit dans des eaux profondes dans un délai assez court.

Désormais, C # 3.0 résout ce problème car C # 3.0 a ajouté de nombreuses fonctionnalités dans lesquelles le compilateur déduit des types au nom du développeur. Les principes antérieurs sur «pas de surprises» et «règles simples» étaient en conflit avec d'autres principes de conception nécessaires pour faire fonctionner LINQ. La fonctionnalité que vous proposez devrait-elle avoir été ajoutée en C # 3.0?

Ça aurait pu. La fonctionnalité réellement ajoutée dans C # 3.0 était:

new[] { x, y, z }

déduit le type du tableau à l'aide de l'algorithme: prenez les expressions pour les éléments qui ont des types, déterminez lequel de ces types est le type le plus général unique vers lequel toutes les autres expressions sont convertibles, et si un tel type existe, choisissez-le. Sinon, produire une erreur,

Cette fonctionnalité aurait pu être davantage assouplie pour rendre l' new[]option. Cela n'a pas été fait.

Maintenant, si vous m'aviez demandé dans la période C # 3.0 de critiquer la fonctionnalité proposée, j'aurais fait remarquer que (1) le compilateur C # 3.0 risquait déjà de faire glisser le calendrier de la version entière, alors n'en ajoutons plus charge de conception, d'implémentation et de test pour une fonctionnalité totalement inutile qui évite à l'utilisateur six frappes, et (2) C # 3.0 a également ajouté des initialiseurs de collection:

new List<int>() { 10, 20, 30 }

pourquoi devrait {10, 20, 30}être automatiquement un tableau ? Pourquoi ne devrait-il pas être un List<int>? Ou l'un des nombreux autres types? Pourquoi le biais vers les tableaux? N'oubliez pas qu'une fois que nous avons choisi de consacrer la syntaxe des tableaux, nous y restons pour toujours . Ce n'est peut-être jamais autre chose, donc la fonctionnalité proposée n'est pas seulement inutile, elle empêche également d'éventuelles fonctionnalités futures qui semblent plausibles.

En résumé: la fonctionnalité proposée violait directement certains des principes de conception de C # 1.0. Cela n'ajoute rien d'autre qu'une charge inutile à C # 3.0. Dans toutes les versions du langage depuis C # 3.0, la fonctionnalité proposée n'a aucun bon argument pour recommander d'y consacrer du temps, des efforts et de l'argent par rapport à de nombreuses autres fonctionnalités plus valables.

Par conséquent, aucune fonctionnalité de ce type.

Eric Lippert
la source
Heh, vous devez obtenir un t-shirt imprimé avec "le monde n'est pas comme vous voulez qu'il soit" imprimé dessus :)
slugster
6
@JoeBlow: Tout d'abord, vous êtes les bienvenus. En ce qui concerne "pourquoi pas" - votre commentaire illustre bien le problème. Lorsque certaines personnes posent une question «pourquoi», elles recherchent une justification logique . Certaines personnes recherchent une justification pragmatique . Et vous recherchez apparemment la ligne de la spécification décrivant la règle . C'est tellement vague qu'il est très difficile d'élaborer une bonne réponse qui cible la question dans l'esprit de celui qui pose la question. Les questions «pourquoi pas» sont encore pires parce qu'elles sont des questions vagues sur des choses qui n'existent même pas .
Eric Lippert
3
@EricLippert C'est encore pire que la simple question sur les choses qui pourraient exister : si vous travaillez sur un logiciel avec une équipe, toute l'équipe passe chaque jour de l'année à réfléchir aux fonctionnalités et à en équilibrer les conséquences. Les décisions sont prises. Les demandes de fonctionnalités et «pourquoi» demande une justification. Cependant, pourquoi ne pas implique que quelqu'un veut juste faire quelque chose, ce qui remet fondamentalement en question le jugement de l'équipe elle-même. Pire encore, la personne qui pose la question pourquoi pas en sait généralement peu sur le sujet. En tant que tel, je pense qu'il est tout à fait juste de repousser les questions pourquoi pas . Bon travail IMO.
atlaste