2011-05-04 13 views
12

Teniendo en cuenta lo siguiente (sin sentido, pero es para propósitos ilustrativos) clase de prueba:dinámico, LINQ y Select()

public class Test 
{ 
    public IEnumerable<string> ToEnumerableStrsWontCompile(IEnumerable<dynamic> t) 
    { 
     return t.Select(x => ToStr(x)); 
    } 

    public IEnumerable<string> ToEnumerableStrsWillCompile(IEnumerable<dynamic> t) 
    { 
     var res = new List<string>(); 

     foreach (var d in t) 
     { 
      res.Add(ToStr(d)); 
     } 

     return res; 
    } 

    public string ToStr(dynamic d) 
    { 
     return new string(d.GetType()); 
    } 
} 

¿Por qué no se compila con el siguiente error, en t.Select(x => ToStr(x))?

Cannot implicitly convert type 'System.Collections.Generic.IEnumerable<dynamic>' 
to 'System.Collections.Generic.IEnumerable<string>'. An explicit conversion 
exists (are you missing a cast?) 

Ningún error en el segundo método.

Respuesta

10

Creo que lo que sucede aquí es que, dado que la expresión ToStr(x) implica una variable dynamic, el tipo de resultado de toda la expresión es también dynamic; es por eso que el compilador cree que tiene un IEnumerable<dynamic> donde espera un IEnumerable<string>.

public IEnumerable<string> ToEnumerableStrsWontCompile(IEnumerable<dynamic> t) 
{ 
    return t.Select(x => ToStr(x)); 
} 

Hay dos maneras de solucionarlo.

Utilice una conversión explícita:

public IEnumerable<string> ToEnumerableStrsWontCompile(IEnumerable<dynamic> t) 
{ 
    return t.Select(x => (string)ToStr(x)); 
} 

Esto le dice al compilador que el resultado de la expresión es, sin duda va a ser una cadena, por lo que terminan con un IEnumerable<string>.

Reemplazar el lambda con un grupo método:

public IEnumerable<string> ToEnumerableStrsWontCompile(IEnumerable<dynamic> t) 
{ 
    return t.Select(ToStr); 
} 

De esta manera el compilador convierte implícitamente la expresión de grupo método a una lambda. Tenga en cuenta que ya que no se menciona la variable dynamicx en la expresión, el tipo de resultado se puede inferir inmediatamente como string porque solo hay un método a considerar, y su tipo de devolución es string.

+2

+1 para la explicación y, en particular, para la versión del Grupo de métodos –

1

Trate de esta manera:

public IEnumerable<string> ToEnumerableStrsWontCompile(IEnumerable<dynamic> t) 
{ 
    return t.Select(ToStr); 
} 

Otra posibilidad es especificar explícitamente los argumentos genéricos:

public IEnumerable<string> ToEnumerableStrsWontCompile(IEnumerable<dynamic> t) 
{ 
    return t.Select<dynamic, string>(x => ToStr(x)); 
} 
+1

Está funcionando, pero ¿por qué? – mathieu

1

Try return t.Select(x => ToStr(x)) as IEnumerable<string>

+2

Está funcionando, pero ¿por qué? – mathieu

1

parecería que el compilador de C# es determinar el tipo de la lambda en el primer método x => ToStr(x) como Func<dynamic, dynamic> y por lo tanto declarar el tipo de la IEnumerable devueltos como IEnumerable<dynamic>. Un pequeño cambio x => (string)ToStr(x) parece solucionarlo.

Esto es más probable debido a las reglas de inferencia de tipo - ya que si se cambia la línea a esto:

return t.Select<dynamic, string>(x => ToStr(x)); 

Se compila sin error.

La regla de inferencia de tipos específicos de que se trate, sin embargo, no estoy muy seguro de - sin embargo, si se toma este código:

public void foo(dynamic d) 
{ 
    var f = this.ToStr(d); 
    string s = f; 
} 

Y luego pasa sobre la 'f' en el editor verá ese intellisense informa el tipo de la expresión como 'dinámico f'.Esto se debe a que this.ToStr(d) es una expresión dinámica, independientemente de si el método en sí y su tipo de devolución se conocen en tiempo de compilación.

El compilador se complace en asignar string s = f; porque es capaz de analizar estáticamente el tipo que f es probable que sea, porque finalmente ToStr siempre devuelve una cadena.

Es por eso que este primer método requiere un molde o parámetros de tipo explícitos, porque el compilador está haciendo que ToStr sea del tipo dynamic; porque tiene al menos una expresión dinámica como parte de ella.

Cuestiones relacionadas