2010-03-07 12 views
5

yo estaba trabajando en una parte los comentarios del público de la solicitud el viernes cuando llegué a un error de desbordamiento de pila, lo que me confunde por lo que pensé en pedir ayuda. ¡Y buscar en la web usando la expresión 'desbordamiento de pila' es un poco contraproducente!error de desbordamiento de pila en C# set/get

que quería hacer un HtmlEncode en la cuenta de juego del campo en la clase, antes de enviar una instancia de la clase que se añade a la base de datos:

public class Feedback 
{ 

    public Feedback() { } 

    public string FeedbackComment 
    { 
     get { return FeedbackComment; } 
     set {System.Web.HttpUtility.HtmlEncode(value); } 
    } 

    // other fields 

    // methods 
} 

Esto causaba Stackoverflow errores, I' he fijado el error cambiando el código para tener este aspecto:

public class Feedback 
{ 

    public Feedback() { } 

    private string feedbackComment; 

    public string FeedbackComment 
    { 
     get { return feedbackComment; } 
     set { feedbackComment = System.Web.HttpUtility.HtmlEncode(value); } 
    } 

    // other fields 

    // methods 
} 

pero yo sólo quería una explicación de por qué los primeros estados get/set eran tan recursivo que causaron un desbordamiento de pila, pero al revertir el código para buscar más como C# 2.0 trabajado? ¿Se puede lograr esto con la sintaxis más corta y, en caso afirmativo, cómo?

Ésta es mi primera pregunta en SO - por favor intente ser suave!

+5

No puedo evitar pensar que este sitio es el lugar perfecto para esta pregunta – jakebman

+0

Tantas respuestas correctas - gracias por toda la ayuda. – amelvin

Respuesta

21

El getter del primer ejemplo está volviendo la propiedad en sí, no un campo de respaldo.

// The property name is "FeedbackComment" 
public string FeedbackComment 
{ 
    // And here you are returning "FeedbackComment" which is 
    // creating the stack overflow 
    get { return FeedbackComment; } 
} 

Desafortunadamente, no hay manera de acortar lo que tiene, propiedades implementado de forma automática (es decir public String FeedbackComment { get; set; }) debe tener bloques get y set vacíos para ser sintácticamente correcta. No hay nada de malo en su segundo ejemplo: sí, es un poco detallado, pero es claro, conciso y hace el trabajo.

+0

+1 Gracias por su asesoramiento que el segundo ejemplo es una elección razonable. – amelvin

4

Usted está recibiendo un desbordamiento de pila en el primer código debido a que su propiedad de captador está devolviendo la propiedad en sí.

Esto hará que el comprador sea invocado una y otra vez hasta que los desbordamientos de pila.

2

El código que estaba causando un StackOverflowException no proporciona un campo de respaldo a la propiedad, el acceso get está volviendo la propiedad en sí, que es lo que causa el desbordamiento de pila. El segundo ejemplo proporciona un campo de respaldo y devuelve su contenido.

2

Parece que está intentando usar la característica auto-implemented properties introducida en C# 3.0, pero haciendo un lío de la sintaxis.

Volviendo FeedbackComment en el acceso get de la FeedbackComment hotel fenomenal es la creación de un bucle auto-referencial que mantiene 'conseguir' la propiedad, por lo que no resulta sorprendente sobre el desbordamiento de pila allí!

La sintaxis correcta para una propiedad implementada automáticamente es la siguiente. Sin embargo, no puede realizar ningún procesamiento en el acceso directo o en el acceso (por definición en realidad).

public class Feedback 
{ 
    public Feedback() { } 

    public string FeedbackComment 
    { 
     get; 
     set; 
    } 

    // other fields 

    // methods 
} 

En su caso, ya que se desea realizar un procesamiento en el 'set' de acceso, haciendo de la manera estándar de utilizar un campo respaldo es lo que desea.

8

El getter se refiere a sí mismo (como señala Andrew) pero el setter también está equivocado.

este código:

set { System.Web.HttpUtility.HtmlEncode(value); } 

... en realidad no establece nada.El método HtmlEncodedevuelve el valor codificado, en realidad no cambia value.

Otra cosa que debes tener en cuenta es que si usted es HtmlEncode -ing en el fondo, lo que necesita HtmlDecode a la salida, de lo contrario puede terminar con múltiples codificaciones (que no son idempotente). Si usted está tratando de "automatizar" las procesos de codificación entonces la clase que normalmente se ve algo como esto:

public class Foo 
{ 
    private string bar; 

    public string Bar 
    { 
     get { return HttpUtility.HtmlDecode(bar); } 
     set { bar = HttpUtility.HtmlEncode(value); } 
    } 

    public string SafeBar 
    { 
     get { return bar; } 
    } 
} 

o se puede invertir la lógica de seguridad/inseguridad, por ejemplo:

public string Bar 
{ 
    get { return bar; } 
    set { bar = HttpUtility.HtmlEncode(value); } 
} 

public string UnsafeBar 
{ 
    get { return HttpUtility.HtmlDecode(value); } 
} 

De cualquier manera su clase debe hacer explícito el hecho de que se está haciendo algún tipo de codificación, de lo contrario si se escribe código como este:

Foo foo1 = new Foo(); 
foo1.Bar = "<test>"; 
Foo foo2 = new Foo(); 
foo2.Bar = foo1.Bar; 

... entonces usted comenzará a ver un montón de caracteres de escape en feos la salida de foo2.Bar. Haga que el contrato de su clase sea claro, debe realizar la codificación y decodificar o no hacer ninguna de las dos.

+0

+1 Puntos buenos :) –

+0

+1 Originalmente tenía un decodificador, pero lo dejé para simplificar el ejemplo. Estoy de acuerdo con todos tus comentarios. – amelvin

1

Creo que le falta comprensión fundamental de las propiedades. Una propiedad no puede contener ningún dato, es solo un par de un método getter y un método setter (también hay propiedades que solo tienen getters o setters).

El método getter es básicamente un método que no toma argumentos y devuelve un valor del tipo de propiedad, el colocador por otro lado es un método sin valor devuelto y un argumento del tipo llamado valor de la propiedad. C# oculta ambos métodos y los combina con una propiedad y puede llamarlos como un campo normal.

Su primera aplicación es equivalente a:

public class Feedback 
{ 
    public string get_FeedbackComment() 
    { 
     return get_FeedbackComment(); 
    } 

    public void set_FeedbackComment(string value) 
    { 
     System.Web.HttpUtility.HtmlEncode(value); 
    } 
} 

Usted puede ver ahora que la recursividad es y en qué consiste tu error. Además, cuando le echas un vistazo al colocador, notarás que no establece nada. El valor de retorno de HtmlEncode no se guardará en ninguna parte. Necesitas proporcionar un campo de respaldo (como el que está en tu segundo fragmento de código).

Sin embargo, hay propiedades implementadas automáticamente en C# 3.0 y superior, que declaras de la siguiente manera. Tenga en cuenta que el compilador de C# creará automáticamente un campo de respaldo, por lo que básicamente ambas formas son las mismas pero gana más flexibilidad con la primera porque con las propiedades implementadas automáticamente no puede agregar un comportamiento más complejo que la simple configuración y recuperación de valores (al menos en la clase donde lo declaras, haciendo que sea virtual abre posibilidades para extender la lógica de propiedad en subclases ...).

public class Feedback 
{ 
    public string FeedbackComment 
    { 
     get; 
     set; 
    } 
} 

Best Regards,
Oliver Hanappi

+0

El ejemplo se simplificó un poco, así que si eso creó otros problemas también es mi culpa. Parte de mi pregunta fue por qué el campo de respaldo solo se creó para el valor predeterminado {get; set;} accessors - y parece que la respuesta es 'por diseño'. – amelvin

2

Recuerde que las propiedades son realmente métodos - que compilador convertirlos a T get_Property() y set_Property(T value) llamadas - no hay almacenamiento (a menos que el uso de propiedades automáticas, pero lo que sucede allí es el compilador crea un campo de respaldo automáticamente.Por lo tanto lo que su ejemplo de desbordamiento de pila se ve como es:

public class Feedback 
{ 

    public Feedback() { } 

    // Getter 
    public string get_FeedBackComment() { 
     return get_FeedBackComment(); 
    } 
    // Setter 
    public void set_FeedBackComment(string value) { 
     System.Web.HttpUtility.HtmlEncode(value); 
    } 
} 

así que su conseguir fue una llamada a la función que la llamó uno mismo para siempre, por lo que la pila se desbordó debido a que cada llamada es un empuje pila. Y el ajuste llamó a una función, pero nunca almacenó su valor en ninguna parte.

+0

+1 Sí, el campo de respaldo que se está creando para el valor predeterminado {get; set;} ahora está despejado. – amelvin

1

Éste es grande ejemplo para la elaboración de la programación recursiva mal uso;)

problema no es con respecto a las propiedades, pero en general de valores rtreiving de cualquier método como:

 

public int GiveMeValue() 
{ 
    return GiveMeValue(); 
} 

public void SetValue(int value) 
{ 
    SetValue(value); 
} 
 

todos modos propiedades DotNet son tipo especial de métodos. ¿no es así?

Cuestiones relacionadas