C# 为什么这会导致堆栈溢出错误?
这会导致StackOverFlow错误,我知道原因,但我想了解更多关于原因的详细信息,以及我的解决方案是如何处理的。好的,首先,当我尝试为属性赋值时,以下代码会导致StackOverFlow错误:C# 为什么这会导致堆栈溢出错误?,c#,.net,C#,.net,这会导致StackOverFlow错误,我知道原因,但我想了解更多关于原因的详细信息,以及我的解决方案是如何处理的。好的,首先,当我尝试为属性赋值时,以下代码会导致StackOverFlow错误: private List<Albums> albums { get { if (Session["albums"] != null) return (List<Albums>)Session["albums"];
private List<Albums> albums
{
get
{
if (Session["albums"] != null)
return (List<Albums>)Session["albums"];
else
return AlbumCollection.GetAlbums();
}
set
{
albums = value;
Session["albums"] = albums;
}
}
为了解决上述问题,我更改了属性的名称,并添加了另一个变量来保存解决StackOverFlow问题的属性值:
private List<Albums> albums = null;
private List<Albums> Albums
{
get
{
if (Session["albums"] != null)
return (List<Albums>)Session["albums"];
else
return AlbumCollection.GetAlbums();
}
set
{
albums = value;
Session["albums"] = albums;
}
}
另外,我是否正确地设置了setter,分配了值,然后为会话[albums]分配了albums中的值?我是否可以改为Session[albums]=value?您正在重新分配给属性本身 在您的情况下,您只使用会话 所以这应该没问题
private List<Albums> albums
{
get
{
if (Session["albums"] == null)
Session["albums"] = AlbumCollection.GetAlbums();
return (List<Albums>)Session["albums"];
}
set
{
Session["albums"] = value;
}
}
这一行的问题在于:
albums = value;
您正在递归地将属性设置为值,该值将一次又一次地调用setter,直到它溢出。那行代码没有意义。把它扔掉
我猜有一种错误的误解,认为属性需要绑定到字段或其他内容。不是。属性本身只是两个不相关的方法,它们之间或字段之间不需要有任何特定的关系。在检索属性值时,只需调用其get方法并使用返回值,在设置其值时,使用适当的value参数调用其set方法。您不需要以某种方式更改setter中的属性值。当您更改get将返回的值时,语义将自动强制执行,因此下次调用get时,它将返回您已经更改的会话[…] 在第一个示例中,setter递归地调用自己。你的第二个解决了这个问题
是的,你本可以这样做的。因为在你的setter中,你正在呼叫。。。setter,它指向setter,并调用。。。二传手。。。而且
set
{
albums = value; // < --- This line calls itself again..
Session["albums"] = albums;
}
您需要做的只是使用会话[相册]作为值的持久存储。。。您不需要一个私有字段——这只是创建一个冗余的值副本。完全消除它,然后放
private List<Albums> Albums
{
get
{
if (Session["albums"] != null)
return (List<Albums>) Session["albums"];
else
return (Session["albums"] = AlbumCollection.GetAlbums());
}
set
{
Session["albums"] = value;
}
}
在没有持久存储的某些场景中,公共属性只有一个私有成员支持字段是完全可以接受的
有关C属性的更多信息,请查看。这一行导致了您的问题,因为它会在无限循环中递归调用getter:
albums = value;
您是正确的,在第一个示例中,您递归调用唱片集设置器无限次,因此堆栈溢出。C属性和方法应始终以大写字母btw开头 在第二个示例中,您可以简单地使用:
Session["albums"] = value;
如果您愿意。您是正确的,问题是当您在第一个代码块中使用相册时,您指的是这个setter/getter。因此,当您在setter中执行albums=value时,您将再次递归调用setter 在内部,编译器将访问器转换为函数,通过自己执行此操作,可以帮助您查看错误:
private List<Albums> albums
{
set
{
albums = value;
Session["albums"] = albums;
}
}
编译后,将变为:
private void set_albums(List<Albums> value)
{
set_albums(value);
Session["albums"] = albums;
}
给Session[相册]打两次电话是一个常见的错误。会话索引是一项涉及字典查找的相对昂贵的操作
private List<Albums> Albums {
get
{
object stored = Session["albums"];
if (stored != null)
return (List<Albums>) stored;
else
{
var newValue = AlbumCollection.GetAlbums();
Albums = newValue;
return newValue;
}
}
set
{
Session["albums"] = value;
}}
所以,如果我有Session[albums]=value,就可以了?@Xaisoft:是的,这就是你所需要的一切。@Xaisoft:这是一种方法;但是,如果在页面处理过程中多次访问Albums属性,则最好将反序列化结果缓存到私有成员中。好的,有点困惑,我应该执行Session[Albums]=value还是Session[Albums]=Albums,还是相同的操作。@Chris,你指的是我在第二次尝试中声明私有变量albums的实际方式吗?这也带来了另一个问题,创建另一个变量如何缓存结果?我不清楚这一点?好吧,我想我可以做到,但我担心如果我不先做albums=value,我会做错。谢谢。我明白你的意思了,不是在if语句中访问会话,而是在我返回相册列表时,先将其存储在对象中,然后检查对象?对吗?在快速搜索之后,这应该可以帮助您: