2010-02-25 1293 views
32

Si hago esto, me siento un System.StackOverflowException:¿Por qué el compilador de C# no detiene las propiedades de sí mismos?

private string abc = ""; 
public string Abc 
{ 
    get 
    { 
     return Abc; // Note the mistaken capitalization 
    } 
} 

entiendo por qué - la propiedad hace referencia a sí mismo, dando lugar a un bucle infinito. (Consulte las preguntas anteriores here y here).

Lo que me pregunto (y lo que no vi respondió en esas preguntas anteriores) es ¿por qué el compilador de C# no detecta este error? Comprueba otros tipos de referencias circulares (clases heredadas de ellos mismos, etc.), ¿verdad? ¿Es solo que este error no fue lo suficientemente común como para merecer la pena? ¿O hay alguna situación en la que no estoy pensando, cuando quieres que una propiedad se refiera a sí misma de esta manera?

+2

Al "hacer referencia a sí mismo", supongo que realmente quiero decir "recursivamente llamándome a sí mismo", pero entiendes la idea. –

Respuesta

42

Puedes ver el motivo "oficial" en el último comentario here.

publicado por Microsoft el 14/11/2008 a 19:52

Gracias por la sugerencia de Visual Studio!

Tienes razón en que fácilmente se podría detectar recursividad propiedad, pero no puede garantizar que no hay nada útil siendo realizada por el recursividad. El cuerpo de la propiedad podría establecer otros campos en el objeto que cambian el comportamiento de la siguiente recursividad, podría cambiar su comportamiento basado en la entrada del usuario de la consola, o incluso podría comportarse de manera distinta de valores aleatorios. En estos casos, una propiedad recursiva de podría cancelar , pero tenemos sin forma de determinar si ese es el caso en tiempo de compilación (sin resolver el problema de detención ).

Por las razones anteriores (y el rompiendo el cambio que se necesitaría para no permitir este ), no seríamos capaces de prohíben propiedades de auto-recursivo.

Alex Turner

Program Manager

Visual C# compilador

+20

Sin embargo, podría ser bueno si produjeron una advertencia del compilador al respecto. Creo que eso sería valioso. – Nick

+0

+1 Buena respuesta completa, de una fuente "oficial". – auujay

+0

Tiene sentido. . . Sin embargo, es seguro decir que probablemente nunca sea una buena idea * crear deliberadamente un captador de propiedades recursivo, ya que solo se detendría si hubiera efectos secundarios y (si entiendo correctamente) se prefieren los métodos a las propiedades en los casos donde hay efectos secundarios? –

1

Probablemente consideraron que sería innecesario complicar el compilador sin ninguna ganancia real.

Descubrirá este error fácilmente la primera vez que llame a esta propiedad.

0

los otros casos casos que verifican (excepto constructor recursiva) no son válidos IL.
Además, todos esos casos, incluso los constructores recursivos) están garantizados para fallar.

Sin embargo, es posible, aunque poco probable, crear intencionalmente una propiedad recursiva útil (usando declaraciones if).

9

La propiedad que se refiere a sí misma no siempre conduce a la recursión infinita y al desbordamiento de la pila. Por ejemplo, esto funciona bien:

int count = 0; 
public string Abc 
{ 
    count++; 
    if (count < 1) return Abc; 
    return "Foo"; 
} 

Por encima es un ejemplo ficticio, pero estoy seguro de que uno podría llegar a código recursivo útil que es similar. El compilador no puede determinar si ocurrirá una recursión infinita (problema de detención).

Generar una advertencia en el caso simple sería útil.

1

En primer lugar, recibirá una advertencia para la variable no utilizada abc.

En segundo lugar, no hay nada malo en la recursión, siempre que no se trate de recurrencia interminable. Por ejemplo, el código puede ajustar algunas variables internas y llamar al mismo getter recursivamente. Sin embargo, para el compilador no es una manera fácil de demostrar que alguna recursión es interminable o no (la tarea es al menos NP). El compilador podría atrapar algunos casos fáciles, pero luego los consumidores se sorprenderían de que los casos más complicados pasen por las comprobaciones del compilador.

11

Otro punto, además de la explicación de Alex, es que intentamos dar advertencias para el código que hace algo que probablemente no pretendas, , de modo que podrías enviar accidentalmente el error.

En este caso particular, ¿cuánto tiempo le ahorraría realmente la advertencia? Una única prueba de ejecución. Encontrarás este error en el momento de probar el código, porque siempre se bloquea y muere de forma horrible. La advertencia en realidad no te compraría mucho de un beneficio aquí. La probabilidad de que haya algún error sutil en una evaluación de propiedad recursiva es baja.

Por el contrario, nos hacemos dan una advertencia si haces algo como esto:

int customerId; 
... 
this.customerId= this.customerId; 

No hay terrible accidente-y-mueren, y el código es un código válido; asigna un valor a un campo. Pero dado que este es un código sin sentido, probablemente no quisiste hacerlo. Dado que no va a morir de manera horrible, le advertimos que hay algo aquí que probablemente no tuvo la intención y que de otro modo no podría descubrir a través de un bloqueo.

+0

Estaba discutiendo sobre esto los comentarios sobre la respuesta de Alex. Su afirmación de que "dado que este es un código sin sentido, probablemente no tuvo la intención de hacerlo. Dado que no va a morir de manera horrible, advertimos que hay algo aquí que probablemente no tenía la intención" parece contradecir su blog publicar aquí: http://blogs.msdn.com/ericlippert/archive/2010/01/25/why-are-unused-using-directives-not-a-warning.aspx – Nick

+1

@Nick: no estoy viendo el contradicción. (Eso no quiere decir que no haya uno: soy grande, contengo multitudes.) Simplemente no veo a qué te refieres. –

+0

@Eric Lippert: Gracias por la referencia de Canción de mí mismo. :-) – jason

Cuestiones relacionadas