2010-05-04 31 views
9

¿Por qué funciona esto? No me quejo, solo quiero saber.¿Por qué funciona esto?

void Test() 
{  
    int a = 1; 
    int b = 2; 

    What<int>(a, b); 
    // Why does this next line work? 
    What(a, b); 
} 

void What<T>(T a, T b) 
{ 

} 

Respuesta

7

El compilador C# admite la inferencia de tipo para genéricos, y también se ve comúnmente si está utilizando la palabra clave var.

Aquí int se infiere a partir del contexto (a y b) y así <int> no es necesario. Mantiene el código más limpio y más fácil de leer a veces.

veces, su código puede ser más clara para leer si deja que el compilador inferir el tipo, a veces puede ser más clara si se especifica explícitamente el tipo. Es una decisión sobre su situación dada.

+0

Él no está usando la palabra clave 'var'. – SLaks

+2

@SLaks: Sí, lo sé. –

+0

@SLaks: "'también' comúnmente visto" – Dykam

5

El compilador infiere el parámetro de tipo genérico de los tipos de parámetros reales que pasó.

Esta función hace que las llamadas LINQ sean mucho más simples. (No es necesario escribir numbers.Select<int, string>(i => i.ToString()), porque el compilador infiere el int de numbers y la string de ToString)

17

Funciona porque a y b son números enteros, por lo que el compilador puede deducir el argumento de tipo genérico para What.

En C# 3, el compilador también puede inferir el argumento de tipo incluso cuando los tipos no coinciden, siempre que una conversión de ampliación tenga sentido. Por ejemplo, si c fuera un long, entonces What(a, c) se interpretaría como What<long>.

Tenga en cuenta que si, por ejemplo, c fuera un string, no funcionaría.

+0

Tenga en cuenta también que si tiene dos tipos diferentes que extienden 'Parent' y usted trata de hacer' What (a, b) '(donde a y b son de esos dos tipos diferentes), no sabrá inferir el escriba como 'Padre'. –

+1

@BlueRaja: ese es en realidad el mismo caso, ya que en el ejemplo de Dan int y string son ambas extensiones de Object. El principio de diseño aquí es que cuando se le pide que encuentre un "mejor" miembro de un conjunto, C# siempre elige un miembro del conjunto. Nunca elige un miembro fuera del conjunto. Si se le pregunta cuál es el mejor miembro de {Tiger, Giraffe}, no dice "Animal", dice que no hay mejor miembro. –

1

El compilador es suficientemente inteligente como para darse cuenta de que el tipo genérico es 'int'

7

Se trata de utilizar la inferencia de tipos de métodos genéricos. Tenga en cuenta que esto ha cambiado entre C# 2 y 3. Por ejemplo, esto no hubiera trabajado en C# 2:

What("hello", new object()); 

... mientras que lo haría en C# 3 (o 4). En C# 2, la inferencia de tipo se realizó por argumento, y los resultados tenían que coincidir exactamente. En C# 3, cada argumento aporta información que luego se junta para inferir los argumentos de tipo. C# 3 también admite multifunción tipo inferencia donde el compilador puede resolver un argumento de tipo, luego ver si tiene más información sobre el resto (por ejemplo, debido a expresiones lambda con tipos de parámetros implícitos). Básicamente continúa hasta que no puede obtener más información, o termina, o ve información contradictoria. La inferencia de tipo en C# no es tan poderosa como el algoritmo Hindley-Milner, pero funciona mejor de otras maneras (en particular, siempre hace avanzar el progreso).

Consulte la sección 7.4.2 de la especificación C# 3 para obtener más información.

2

El compilador puede inferir que el tipo T es un int ya que ambos parámetros pasados ​​a What() son de tipo int. Notarás que muchas de las extensiones de Linq se definen con genéricos (como IEnumerable) pero normalmente se usan de la manera que se muestra.

Cuestiones relacionadas