2008-09-05 8 views
44

C# no requiere que especifique un parámetro de tipo genérico si el compilador puede inferir que, por ejemplo:¿Por qué C no admite tipos genéricos implícitos en los constructores de clases?

List<int> myInts = new List<int> {0,1,1, 
    2,3,5,8,13,21,34,55,89,144,233,377, 
    610,987,1597,2584,4181,6765}; 

//this statement is clunky 
List<string> myStrings = myInts. 
    Select<int,string>(i => i.ToString()). 
    ToList<string>(); 

//the type is inferred from the lambda expression 
//the compiler knows that it's taking an int and 
//returning a string 
List<string> myStrings = myInts. 
    Select(i => i.ToString()). 
    ToList(); 

Esto es necesario para los tipos anónimos en los que no se sabe lo que sería el parámetro de tipo (en intellisense aparece como 'a) porque es agregado por el compilador. los parámetros de tipo

de nivel de clase no le permiten hacer esto:

//sample generic class 
public class GenericDemo<T> 
{ 
    public GenericDemo (T value) 
    { 
     GenericTypedProperty = value; 
    } 

    public T GenericTypedProperty {get; set;} 
} 

//why can't I do: 
int anIntValue = 4181; 
var item = new GenericDemo(anIntValue); //type inference fails 

//however I can create a wrapper like this: 
public static GenericDemo<T> Create<T> (T value) 
{ 
    return new GenericDemo<T> (value); 
} 

//then this works - type inference on the method compiles 
var item = Create(anIntValue); 

¿Por qué no C# soportar este nivel de clase de tipo genérico inferencia?

+0

¿Por qué esta pregunta tiene un voto para cerrar contra ella como un duplicado de [¿Por qué el constructor de C no puede inferir el tipo?] (http://stackoverflow.com/questions/3570167) cuando esa pregunta es dos años más reciente? Seguramente ese es el duplicado? – Keith

+0

Creo que la otra pregunta es más concisa y tiene una mejor respuesta. – Sam

+0

@Sam - sí, la respuesta de Eric Lippert a esa pregunta es autoritativa, pero no creo que ninguna de las dos preguntas deba cerrarse. – Keith

Respuesta

25

En realidad, su pregunta no está nada mal. He estado jugando con un lenguaje de programación genérico en los últimos años y aunque nunca he llegado a desarrollarlo (y probablemente nunca lo haya hecho), he pensado mucho sobre la inferencia de tipo genérico y una de mis principales prioridades es siempre ha sido para permitir la construcción de clases sin tener que especificar el tipo genérico.

C# simplemente carece del conjunto de reglas para que esto sea posible. Creo que los desarrolladores nunca vieron la necesidad de incluir esto. En realidad, el siguiente código estaría muy cerca de tu proposición y resolvería el problema. Todas las necesidades de C# son un soporte de sintaxis agregado.

class Foo<T> { 
    public Foo(T x) { … } 
} 

// Notice: non-generic class overload. Possible in C#! 
class Foo { 
    public static Foo<T> ctor<T>(T x) { return new Foo<T>(x); } 
} 

var x = Foo.ctor(42); 

Dado que este código funciona en realidad, hemos demostrado que el problema no es de semántica sino simplemente uno de falta de apoyo. Creo que tengo que recuperar mi publicación anterior. ;-)

11

¿Por qué C# no admite esta inferencia de tipo genérico de nivel de clase?

Porque generalmente son ambiguas. Por el contrario, la inferencia de tipo es trivial para llamadas a funciones (si todos los tipos aparecen en argumentos). Pero en el caso de llamadas de constructor (funciones glorificadas, por el bien de la discusión), el compilador tiene que resolver múltiples niveles al mismo tiempo. Un nivel es el nivel de clase y el otro es el nivel de argumentos del constructor. Creo que resolver esto es algorítmicamente no trivial. Intuitivamente, diría que es incluso NP completo.

Para ilustrar un caso extremo en que la resolución es imposible, imaginar la siguiente clase y dime lo que el compilador debe hacer:

class Foo<T> { 
    public Foo<U>(U x) { } 
} 

var x = new Foo(1); 
+0

Por la forma en que se formula la pregunta de Konrad, ya sé que el tipo "int" no puede inferirse simplemente del "nuevo Foo (1)", por ejemplo, pero ¿alguien podría explicarme por qué no? Quiero decir, si digo "var x = 1", termino con un int, entonces, ¿cómo es eso diferente de este ejemplo? –

+0

No creo * Porque generalmente son ambiguos * es una muy buena razón; los métodos genéricos también son ambiguos, en presencia de los no genéricos con las mismas firmas. – Sam

+0

@Sam Estoy totalmente de acuerdo, de ahí veo mi otra respuesta (aceptada). Sin embargo, creo que este * es * el motivo original por el que no existen en C#. Esta pregunta es realmente antigua y las respuestas se escribieron antes de que Stack Overflow aplicara reglas más estrictas con respecto a las respuestas, y antes de que se implementaran los comentarios; como consecuencia, todo este hilo lee más que una discusión (lo que era). La única razón por la que no eliminé esta respuesta es porque de lo contrario el resto de las respuestas aquí se vuelven aún más confusas –

2

Gracias Konrad, eso es una buena respuesta (1), pero sólo para ampliar en eso.

Supongamos que C# tiene una función constructora explícita:

//your example 
var x = new Foo(1); 

//becomes 
var x = Foo.ctor(1); 

//your problem is valid because this would be 
var x = Foo<T>.ctor<int>(1); 
//and T can't be inferred 

Tienes toda la razón de que el primer constructor no puede deducirse.

Ahora vamos a volver a la clase

class Foo<T> 
{ 
    //<T> can't mean anything else in this context 
    public Foo(T x) { } 
} 

//this would now throw an exception unless the 
//typeparam matches the parameter 
var x = Foo<int>.ctor(1); 

//so why wouldn't this work? 
var x = Foo.ctor(1); 

Por supuesto, si añado el constructor de nuevo (con su tipo alternativo) tenemos una llamada ambigua - exactamente como si una sobrecarga del método normal no podía ser resuelto.

Cuestiones relacionadas