Imagina que tienes esto en alguna parte
public static T AnyOne<T>(this T[] ra) where T:class
{
int k = ra.Length;
int r = Random.Range(0,k);
return ra[r];
}
o incluso solo esto
public static string OneOf(this string[] strings)
{
return "a";
}
Entonces, por supuesto que puedes hacer esto ...
string[] st = {"a","b","c"};
string letter = st.AnyOne();
... Lo cual es genial. PERO. Parece que NO puede hacer esto:
string letter = {"a","b","c"}.AnyOne();
o de hecho tal vez esto
string letter = ( {"a","b","c"} ).AnyOne();
o cualquier otra cosa que probé.
De hecho (1) ¿por qué no se puede hacer eso? y (2) me estoy perdiendo algo, ¿cómo harías eso si hubiera una manera?
Respuestas:
Primero tienes que crear la matriz, usando
new[]
.string letter = (new[] {"a","b","c"}).AnyOne();
Como @hvd mencionó, puede hacer esto sin paréntesis
(..)
, agregué los paréntesis porque creo que es más legible.string letter = new[] {"a","b","c"}.AnyOne();
Y puede especificar el tipo de datos
new string[]
como se ha mencionado en otras respuestas.No puede simplemente hacer
{"a","b","c"}
, porque puede pensar en ello como una forma de completar la matriz, no de crearla.Otra razón será que el compilador estará confundido, no sabrá qué crear, por ejemplo, a
string[]{ .. }
o aList<string>{ .. }
.Usando solo el
new[]
compilador puedes saber por tipo de datos (".."
), entre{..}
, lo que quieres (string
). La parte esencial es[]
que eso significa que desea una matriz.Ni siquiera puedes crear una matriz vacía con
new[]
.string[] array = new []{ }; // Error: No best type found for implicity-typed array
fuente
string letter = new[] {"a","b","c"}.AnyOne();
está bien. Si los quieres, si crees que es más legible entre paréntesis, son válidos, pero en ese caso creo que al menos vale la pena mencionar que es una elección consciente de tu parte, que no fue forzada por el idioma.Esta línea:
string[] st = {"a","b","c"};
es una abreviatura de una expresión de creación de matriz equivalente (en ILSpy )
string[] st = new string[] {"a","b","c"};
Esto
string[] st = {"a","b","c"}
solo se puede usar en el momento de la declaración , no puede no usarlo en otro lugar, ni siquiera puede hacer:string[] st; st = {"a", "b", "c"}; //Error
Se explica en la Sección 7.6.10.4 para la expresión de creación de matrices en las especificaciones del lenguaje C #.
Entonces, esto
"{"a", "b", "c"}"
solo sin uso en la declaración no significa nada. Por lo tanto, no puede usarlo con su método de extensión, ya que su método de extensión opera en una matriz.Ya mencionado en la respuesta de @ adricadar , puede hacer:
(new[] {"a","b","c"}).AnyOne();
o
(new string[] {"a","b","c"}).AnyOne();
fuente
Rechazo las preguntas del tipo "por qué no" porque, en primer lugar, las respuestas casi nunca son satisfactorias; ya has obtenido la respuesta "la función no es la que quieres porque la especificación no dice lo que quieres que diga". , que imagino que no fue una respuesta particularmente satisfactoria. En segundo lugar, el equipo de diseño no tiene que justificar por qué el mundo no es como usted desea que sea; las funciones no existen de forma gratuita y luego se diseñan fuera del idioma; más bien, las características deben justificarse primero y luego diseñarse.
Así que intentemos hacer su pregunta de "por qué no" un poco más clara. La característica existente es "se puede usar un inicializador de matriz (a) en el lado derecho de los iguales en una inicialización o (b) a la derecha de una construcción de objeto de tipo matriz". La característica propuesta es: "un inicializador de matriz también se puede utilizar como expresión". La pregunta es "¿qué críticas haría Eric sobre la función propuesta?"
La primera crítica que haría es que no está claro cuál es el tipo de expresión. En un inicializador de variable tienes el tipo de variable y en una expresión de creación de objeto tienes el tipo de objeto; de ambos podemos deducir el tipo de matriz construida. Sin ninguna pista, ¿qué tipo debemos deducir?
En C # 1.0, cuando se agregó esta característica, hubo un gran total de inferencias de tipo cero hechas en el lenguaje. Un principio de diseño en los primeros días de C # era "sin sorpresas" y que el compilador no era "demasiado inteligente". Si el desarrollador tiene la intención de que una expresión sea de un tipo particular, ese tipo debería ser de alguna manera obvio en la expresión. Cuando tu dices
new double[] { 1, 2, 3.4 }
está bastante claro qué tipo se pretende. similar
new Animal[] { cat, dog, null }
La característica propuesta viola este principio. La expresión debe tener un tipo, pero de ninguna manera está claro cuál es el tipo de argumento en
M({cat, dog, null})
Además: supongamos que tenemos dos sobrecargas de
M
, una de las cuales toma una matriz deAnimal
y otra que toma una matriz deIPet
. ¿Qué sobrecarga deM
es aplicable? ¿Es una de las conversiones mejor que la otra? Los tipos de elementos sonCat
yDog
; ¿Tiene sentido deducir un tipo que ni siquiera aparece ahí? Todas estas son preguntas que deben ser consideradas por el equipo de diseño, y estas son preguntas que de ninguna manera tienen respuestas obvias. La característica propuesta nos lleva a aguas profundas en muy poco tiempo.Ahora, C # 3.0 resuelve este problema porque C # 3.0 agregó numerosas características donde el compilador infiere tipos en nombre del desarrollador. Los principios anteriores sobre "sin sorpresas" y "reglas simples" estaban en conflicto con otros principios de diseño necesarios para que LINQ funcione. ¿Debería haberse agregado la característica que propone en C # 3.0?
Podría haber sido. La característica realmente agregada en C # 3.0 fue:
new[] { x, y, z }
infiere el tipo de la matriz usando el algoritmo: tome las expresiones para los elementos que tienen tipos, determine cuál de esos tipos es el tipo único más general al que todas las demás expresiones son convertibles, y si tal tipo existe, elija ese. De lo contrario producirá un error,
Esa característica podría haberse relajado aún más para convertirla en
new[]
opcional. Esto no se hizo.Ahora, si me hubieras pedido en el marco de tiempo de C # 3.0 que criticara la característica propuesta, habría señalado que (1) el compilador de C # 3.0 ya estaba en grave peligro de retrasar el cronograma de toda la versión, así que no agreguemos más carga de diseño, implementación y prueba para una característica completamente innecesaria que le ahorra al usuario seis pulsaciones de teclas, y (2) C # 3.0 también agregó inicializadores de colección:
new List<int>() { 10, 20, 30 }
¿Por qué debería
{10, 20, 30}
ser automáticamente una matriz ? ¿Por qué no debería ser unList<int>
? ¿O cualquiera de otros tipos? ¿Por qué el sesgo hacia las matrices? Recuerde, una vez que elegimos consagrar la sintaxis de las matrices, estaremos atrapados con ella para siempre . Puede que nunca sea otra cosa, por lo que la función propuesta no solo es innecesaria, sino que también evita posibles funciones futuras que parecen plausibles.Resumiendo: la característica propuesta violó directamente algunos de los principios de diseño de C # 1.0. Agrega nada más que una carga innecesaria a C # 3.0. En todas las versiones del lenguaje desde C # 3.0, la característica propuesta no tiene un buen argumento para recomendar gastar tiempo, esfuerzo y dinero en ella sobre muchas otras características más valiosas.
Por lo tanto, no existe tal característica.
fuente