¿No puede usar una matriz "en línea" en C#?
(3)
(1) ¿por qué no se puede hacer eso?
{"a","b","c"}.AnyOne();
Esta línea:
string[] st = {"a","b","c"};
es una abreviatura para una expresión de creación de matriz equivalente (bajo ILSpy )
string[] st = new string[] {"a","b","c"};
Esta
string[] st = {"a","b","c"}
solo se puede usar en el momento de la declaración
, no se puede usar en otro lugar, ni siquiera se 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 especificaciones de lenguaje C #.
Así que este
"{"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.
(2) me estoy perdiendo algo, ¿cómo harías eso si hay una manera?
Ya mencionado en la answer @ adricadar, puede hacer:
(new[] {"a","b","c"}).AnyOne();
o
(new string[] {"a","b","c"}).AnyOne();
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, puedes hacer esto ...
string[] st = {"a","b","c"};
string letter = st.AnyOne();
... Lo cual es genial. PERO. Parece que NO puedes hacer esto:
string letter = {"a","b","c"}.AnyOne();
o 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 hay una manera?
Primero debe crear la matriz, utilizando
new[]
.
string letter = (new[] {"a","b","c"}).AnyOne();
Como @hvd mencionó que puede hacer esto sin paréntesis
(..)
, agregué las 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 él como una forma de llenar la matriz, no de crearla.
Otra razón será que el compilador estará confundido, no sabrá qué crear, por ejemplo, una
string[]{ .. }
o una
List<string>{ .. }
.
Usando el
new[]
compilador
new[]
puede saber por
tipo de datos
(
".."
), entre
{..}
, lo que desea (
string
).
La parte esencial es
[]
, eso significa que quieres una matriz.
Ni siquiera puede crear una matriz vacía con
new[]
.
string[] array = new []{ }; // Error: No best type found for implicity-typed array
Rechazo las preguntas de "por qué no" porque primero, las respuestas casi nunca son satisfactorias: ya has recibido 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. Segundo, el equipo de diseño no tiene que justificar por qué el mundo no es como tú quieres que sea; las funciones no existen de forma gratuita y luego están diseñadas fuera del lenguaje; más bien, las características tienen que justificarse primero y luego diseñarse.
Así que tratemos de hacer que su pregunta "por qué no" sea un poco más nítida. 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 usar como una expresión". La pregunta es "¿qué críticas haría Eric de la característica 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 tiene el tipo de variable y en una expresión de creación de objeto, tiene 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 realizadas 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 pretende 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
M({cat, dog, null})
Además: supongamos que tenemos dos sobrecargas de
M
, una de las cuales toma una matriz de
Animal
y otra que toma una matriz de
IPet
.
¿Qué sobrecarga de
M
es aplicable?
¿Una de las conversiones es mejor que la otra?
Los tipos de los elementos son
Cat
y
Dog
;
¿Tiene sentido deducir un tipo que ni siquiera aparece allí?
Todas estas preguntas 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 en las que 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 funcionara. ¿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 }
deduce el tipo de matriz usando el algoritmo: tome las expresiones para los elementos que tienen tipos, determine cuál de esos tipos es el tipo más general único al que todas las otras expresiones son convertibles, y si tal tipo existe, elija eso. De lo contrario producirá un error,
Esa característica podría haberse relajado aún más para hacer que el
new[]
opcional.
Esto no fue hecho.
Ahora, si me hubiera pedido en el plazo 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 perder el cronograma para todo el lanzamiento, así que no agreguemos más carga de diseño, implementación y pruebas para una característica completamente innecesaria que 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é
{10, 20, 30}
debería ser automáticamente una
matriz
?
¿Por qué no debería ser una
List<int>
?
¿O alguno de varios otros tipos?
¿Por qué el sesgo hacia las matrices?
Recuerde,
una vez que elegimos consagrar la sintaxis para las matrices, nos quedamos con ella para siempre
.
Puede que nunca sea
otra
cosa, por lo que la característica propuesta no solo es innecesaria, sino que también evita posibles características futuras que parecen plausibles.
En resumen: la característica propuesta viola directamente algunos de los principios de diseño de C # 1.0. No 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 hay tal característica.