处理对象时出现StackOverflowException

时间:2015-06-05 13:10:38

标签: c# asp.net stack-overflow dispose

我创建了一个类来将搜索值存储到会话中。这样,当我从另一个页面返回搜索页面时,我可以获得存储在会话中的值。加载搜索页面时,我从会话中获取值,填充文本字段并随后处理该对象。但是当我尝试处理对象时,我得到StackOverflowException。为什么会发生这种情况?如何解决?

    public class SearchValue : IDisposable{
          public int ID {get; set;}
          public string Name {get; set;}

          public void Dispose()
          {
              this.Dispose();
          }
     }

            public void SaveSearchValueToSession()
            {
                SearchValue searchValue = new SearchValue();
                searchValue.ID = Convert.ToInt32(txtID.Text);
                searchValue.Name = txtName.Text;
                Session["SEARCH_VALUE"] = searchValue;
            }

protected void Page_Load(object sender, EventArgs e){
      SearchValue searchValue = (SearchValue)Session["SEARCH_VALUE"];
      txtID.Text = searchValue.ID.ToString();
      txtName.Text = searchValue.Name;

      //Right here I would like to dispose the object
      searchValue.Dispose()
}

3 个答案:

答案 0 :(得分:5)

您正在Dispose方法中调用相同的方法。这确实会导致StackOverflowException。我想知道你是否真的需要实施IDisposable,如果你了解它的目的......

如果你真的需要:

  1. 提供meaningful implementation of Dispose,免费的非托管资源等;
  2. 在变量周围使用using;
  3. 弃置后不要将其保存在Session内。
  4. 另请阅读Fundamentals of Garbage Collection

    从评论中我注意到你担心会创建太多的对象。别担心,这里没问题。这尤其正确,因为您的对象(单个)现在不会收集垃圾:您将其保存在会话中,直到会话被破坏为止。你一遍又一遍地重复使用同一个对象。

答案 1 :(得分:2)

您的问题源于实施IDisposable模式的不正确方法。以下是实现它的简短但完整的示例:

public class ThisIsDisposable : IDisposable
{
    public ThisIsDisposable() { }

    private bool _isDisposed = false;
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            if (!_isDisposed)
            {
                //Do your unmanaged disposing here
                _isDisposed = true;
            }
        }
    }
}

如果该类为sealed,则第二个Dispose(bool)方法应标记为private而不是虚拟。 IDisposable的主要用途是处置非托管资源。如果您没有非托管资源,您仍然可以实现它,以便可以在using语句中使用该对象,但通常Dispose(bool)重载在这种情况下不会执行任何操作。

请参阅CA1063(https://msdn.microsoft.com/en-us/library/ms244737.aspx)和IDisposable界面(https://msdn.microsoft.com/library/system.idisposable.aspx

正如您的评论所说,使用IDisposable不会自动释放内存。当没有对该对象的引用时,您的对象将被垃圾收集。存储对您的值的引用并且永远不会删除这些引用会导致内存泄漏,因此如果您想确保不泄漏内存,那么您需要确保没有更多对这些引用的活动引用你创建(清除列表/会话对象等)。

在您的情况下,完全没有必要实现此模式,因为您的对象未在using语句中使用,并且它们不会消耗托管资源。

答案 2 :(得分:0)

使用会话是一场艰苦的战斗。就个人而言,我只是将它们用于帐户登录状态。查询字符串可以帮助您。请参阅下面的示例。

之前的页面

Response.Redirect("http://yoursite.com/search?id=12");

然后在搜索页面上(假设)(页面加载)

// usual if(!Page.PostBack)

int searchId = -1;
if(Request.QueryString.Count > 0)
{
   String searchIdStr = Request.QueryString["id"]
   if(searchIdStr != String.Empty)
   {
       try{ 
          searchId = Convert.ToInt32(searchIdStr); 
          SearchValue searchValue = searchValueRepo.GetSearchValues()
            .Find(o => o.ID == searchId);
          if(searchValue == null){
             //Failed to find your search values
          }
       } catch (Exception ex) { //failed to convert to integer };

   }
}

然后,如果您认为用户对查询字符串有太多控制权,那么您可以设置id=239847hcjdhnsjk或盐渍哈希,这样就没有人可以尝试更改该值来更改网站的行为。< / p>