C# 异常的问题

C# 异常的问题,c#,asp.net,nullreferenceexception,C#,Asp.net,Nullreferenceexception,我在ASP.NET项目的C类顶部声明了一个List类型的变量。在load方法中,我实例化了这个类,但是当我尝试在另一个方法中使用load方法中已经实例化的这个对象时,它是null,这给了我一个错误ArgumentNullException。 我是这样做的: public partial class Teste : System.Web.UI.Page { List<Foo> myList; protected void Page_Load(object sender

我在ASP.NET项目的C类顶部声明了一个List类型的变量。在load方法中,我实例化了这个类,但是当我尝试在另一个方法中使用load方法中已经实例化的这个对象时,它是null,这给了我一个错误ArgumentNullException。 我是这样做的:

public partial class Teste : System.Web.UI.Page
{
    List<Foo> myList;

    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
            myList = new List<Foo>();
    }

    protected void btnTeste_Click(object sender, EventArgs e)
    {
        myList.Add(new Foo { Id = 0, Name = "Nobody" }); //NullReferenceException - myList is null here!
    }
}
这可能很简单,但我对web表单还不熟悉,所以我不知道这里发生了什么。我知道在windows窗体中,它可以正常工作。 我让它工作的唯一方法是声明为静态:

static List<Foo> myList;
但我认为这不是正确的方法


任何帮助都将不胜感激。

您必须在每次回发时初始化所有变量,因为所有变量和控件都是在页面生命周期结束时释放的,所以在页面呈现并发送到客户端之后

因此,替换

 if (!IsPostBack)
    myList = new List<Foo>();

您也不应该在ASP.NET中使用静态字段,因为它们是跨所有请求共享的。这意味着每个用户都有相同的列表

如果要在回发过程中保留列表,可以使用会话。但我建议不要这样做。为什么需要将其存储在服务器内存中?如果需要将其用作Repeater或GridView等web数据绑定控件的数据源,则不需要存储它。只需让ViewState恢复控件的状态。默认情况下,这是自动完成的。

在每个PostbBack上,您的变量将为null。你必须提供一种方法来再生它。如果您想以简单的方式执行此操作,请使用ViewState

您仅在以下情况下实例化!我回来了。按钮单击事件是回发。你需要根据你想要完成的事情重新设计你的逻辑。列表中存储了什么?如果您打算重复使用或在多个页面上使用,请考虑将对象放置在会话缓存中。

将其作为静态将无助于空引用异常。 您需要了解您的支票,如果!我会在页面加载事件中返回,并记住Web是无状态的

因此,在第一次加载页面时,列表是实例化的。接下来发生的事情是当你点击你的按钮。现在它是一个职位回来,这将导致!IsPostBack检查返回false。在这里,人们会认为列表之前已经实例化,不需要再次实例化。但是web是无状态的,因此在加载页面时,列表的内容已丢失,并再次设置为空

你需要保持你的状态。有多种方法可以做到这一点,ViewState、Session和cookies会出现在脑海中。阅读并相应地使用它们

在您的情况下,您可以:

protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
        myList = new List<Foo>();
        Session["myList"] = myList;
    }
    else
    {
        myList = Session["myList"] as List<Foo>;
    }
}
这将恢复回邮时的原始列表。但是请记住,会话是昂贵的,因为它们是在服务器上按用户维护的

您也可以使用ViewState,但这需要一个可序列化的对象

要使类可序列化,请参见:

然后您可以在上面的代码中使用ViewState而不是Session。ViewState的优点是,它将在客户端按页面进行维护,并且不会像在会话中那样对服务器造成负担。因此,您的ViewState代码如下所示:

protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
        myList = new List<Foo>();
        ViewState["myList"] = myList;
    }
    else
    {
        myList = ViewState["myList"] as List<Foo>;
    }
}

您可能会看到:

虽然这将解决NRE的问题,但最终会在每个帖子上都有一个新的列表,我认为这不是必需的。@Habib:我不知道是否需要,但我也怀疑这一点。我已经编辑了我的答案。ViewState需要可序列化的数据。这是真的,但仍然比放入会话要好。至少viewstate仅适用于当前页面。这不是最好的选择,因为它会使客户端下载的文件更重。然而,这更多的是为了展示这个概念。绝对正确。我只是觉得你应该在你的回答中提到它。我会在下一个回答中更加小心。谢谢你的输出。谢谢@Habib的解释,我会用ViewState完成的。我很感激!
protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
        myList = new List<Foo>();
        Session["myList"] = myList;
    }
    else
    {
        myList = Session["myList"] as List<Foo>;
    }
}
protected void btnTeste_Click(object sender, EventArgs e)
{
    myList.Add(new Foo { Id = 0, Name = "Nobody" });
    Session["myList"] = myList; //save it back in session
}
[Serializable]
class Foo
{
  public int ID { get; set;}
  public string Name {get; set;}
}
protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
        myList = new List<Foo>();
        ViewState["myList"] = myList;
    }
    else
    {
        myList = ViewState["myList"] as List<Foo>;
    }
}
protected void btnTeste_Click(object sender, EventArgs e)
{
    myList.Add(new Foo { Id = 0, Name = "Nobody" });
    ViewState["myList"] = myList; //save it back in session
}