当我遇到堆栈溢出错误时,我正在处理应用程序的公共注释部分,这让我很困惑,所以我想我会请求帮助。使用“堆栈溢出”这个表达式搜索网页有点弄巧成拙!
我想在发送要添加到数据库的类的实例之前,在类的字段的set语句中执行HtmlEncode:
public class Feedback
{
public Feedback() { }
public string FeedbackComment
{
get { return FeedbackComment; }
set {System.Web.HttpUtility.HtmlEncode(value); }
}
// other fields
// methods
}
这导致了StackOverflow错误,我通过将代码更改为以下内容来修复错误:
public class Feedback
{
public Feedback() { }
private string feedbackComment;
public string FeedbackComment
{
get { return feedbackComment; }
set { feedbackComment = System.Web.HttpUtility.HtmlEncode(value); }
}
// other fields
// methods
}
但我只想解释为什么第一个get / set语句如此递归以至于导致堆栈溢出但是当将代码恢复为更像c#2.0时?这可以通过更短的语法来实现,如果是这样的话?
这是我的第一个问题 - 请尽量保持温和!
答案 0 :(得分:21)
第一个示例的getter返回属性本身,而不是返回支持字段。
// The property name is "FeedbackComment"
public string FeedbackComment
{
// And here you are returning "FeedbackComment" which is
// creating the stack overflow
get { return FeedbackComment; }
}
不幸的是,没有办法缩短你拥有的东西,自动实现的属性(即public String FeedbackComment { get; set; }
)必须有空的getter和setter块才能在语法上正确。你的第二个例子没有任何问题 - 是的,它有点冗长,但它很清晰,简洁,并且完成了工作。
答案 1 :(得分:8)
getter引用自身(正如Andrew指出的那样),但是setter也是错误的。
此代码:
set { System.Web.HttpUtility.HtmlEncode(value); }
...实际上没有设置任何东西。 HtmlEncode
方法返回编码值,但实际上并未更改value
。
你应该记住的另一件事是,如果你正在进行HtmlEncode
,你需要在出路时HtmlDecode
,否则你最终会得到多种编码(不是幂等的)。如果您正在尝试“自动化”编码过程,那么该类通常看起来像这样:
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; }
}
}
或者您可以反转安全/不安全逻辑,例如:
public string Bar
{
get { return bar; }
set { bar = HttpUtility.HtmlEncode(value); }
}
public string UnsafeBar
{
get { return HttpUtility.HtmlDecode(value); }
}
无论哪种方式,你的类应该明确表示它正在进行某种编码,否则如果你编写这样的代码:
Foo foo1 = new Foo();
foo1.Bar = "<test>";
Foo foo2 = new Foo();
foo2.Bar = foo1.Bar;
...然后你会在foo2.Bar
的输出中看到一堆丑陋的转义字符。明确你的课程合同,它应该执行 编码和解码,或者不执行任何操作。
答案 2 :(得分:4)
您在第一个代码中遇到堆栈溢出,因为您的属性getter正在返回属性本身。
这将导致再次调用getter,并再次调用,直到堆栈溢出。
答案 3 :(得分:2)
导致StackOverflowException的代码没有为属性提供支持字段,get访问器返回属性本身,这是导致堆栈溢出的原因。第二个示例提供了一个支持字段并返回其内容。
答案 4 :(得分:2)
听起来您正在尝试使用C#3.0中引入的auto-implemented properties功能,但会使语法变得混乱。
在FeedbackComment
属性的get访问器中返回FeedbackComment
正在创建一个自我引用的循环来保持“获取”属性,所以对于那里的堆栈溢出并不感到惊讶!
自动实现属性的正确语法如下。但是,它无法在get或set访问器中执行任何处理(根据定义)。
public class Feedback
{
public Feedback() { }
public string FeedbackComment
{
get;
set;
}
// other fields
// methods
}
在您的情况下,既然您想对'set'访问器进行处理,那么使用支持字段的标准方法就是您想要的。
答案 5 :(得分:2)
请记住,属性实际上是方法 - 它们将编译器转换为T get_Property()
和set_Property(T value)
调用 - 没有存储(除非使用自动属性,但是会发生什么,编译器会创建一个支持字段所以你的堆栈溢出示例是什么样的:
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);
}
}
所以你的获取是一个永远称为自我的函数调用,因此堆栈溢出,因为每次调用都是一个堆栈推送。并且该设置称为函数,但从未将其值存储在任何位置。
答案 6 :(得分:1)
我认为你缺乏对属性的基本理解。属性不能保存任何数据,它只是一对getter方法和setter方法(还有一些属性只有getter或setter)。
getter方法基本上是一个不带参数并返回属性类型值的方法,另一方面,setter是一个没有返回值的方法和一个名为value的属性类型的参数。 C#隐藏了这两种方法并将它们组合到一个属性中,你可以像普通字段一样调用它们。
您的第一个实施相当于:
public class Feedback
{
public string get_FeedbackComment()
{
return get_FeedbackComment();
}
public void set_FeedbackComment(string value)
{
System.Web.HttpUtility.HtmlEncode(value);
}
}
您现在可以看到递归的位置以及错误所在的位置。另外,当你看一下setter时,你会注意到它没有设置任何东西。 HtmlEncode的返回值不会保存在任何地方。您需要提供一个支持字段(如第二段代码中的那个)。
然而,在C#3.0及更高版本中有自动实现的属性,您可以通过以下方式声明这些属性。请注意,C#编译器会自动创建一个支持字段,因此基本上两种方式都是相同的,但是第一种方法可以获得更大的灵活性,因为使用自动实现的属性,您不能添加比简单设置和检索值更复杂的行为(至少在你声明它的类中,使它成为虚拟打开的可能性,以扩展子类中的属性逻辑。)。
public class Feedback
{
public string FeedbackComment
{
get;
set;
}
}
最诚挚的问候,
Oliver Hanappi
答案 7 :(得分:1)
这是详细说明误用递归编程的好例子;)
问题不在于属性,而在于通常使用以下任何方法获得价值:
public int GiveMeValue()
{
return GiveMeValue();
}
public void SetValue(int value)
{
SetValue(value);
}
无论如何,DotNet属性是特殊类型的方法。不是吗?