ArgumentNullException 的问题

Problems with ArgumentNullException

我在 ASP.NET 项目的 C# class 顶部声明了一个 List<Foo> 类型的变量。在加载方法中,我实例化了这个 class,但是当我尝试在另一个方法中使用这个对象(已经在加载方法中实例化)时,它是空的,给我错误 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!
    }
}

这可能很简单,但我是网络表单的新手,所以我不知道这里发生了什么。我知道在 windows 形式中它工作得很好。 我让它工作的唯一方法是声明为静态:

static List<Foo> myList;

但我认为这不是正确的做法。

如有任何帮助,我们将不胜感激。

您必须在每次回发时初始化所有变量,因为所有变量(和控件)都在页面生命周期结束时处理,因此在呈现并发送到客户端之后。

所以替换

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

myList = new List<Foo>();

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

如果你想在回发中保留列表,你可以使用 Session。但我反对这样做。为什么你需要将它存储在服务器内存中?如果您需要将它用作 DataSource 用于 Web 数据绑定控件,例如 RepeaterGridView,则不需要存储它。只需让 ViewState 恢复控件的状态即可。这是默认自动完成的。

在每个 PostbBack 上,您的变量都将为空。您必须提供一种重新生成它的方法。如果您想以简单的方式进行操作,请使用 ViewState.

if (!IsPostBack)
{
     myList = new List<Foo>();
     ViewState["myList"] = myList;
}
else
{
     myList = (List<Foo>)ViewState["myList"];
}

protected void btnTeste_Click(object sender, EventArgs e)
{
    myList.Add(new Foo { Id = 0, Name = "Nobody" }); //NullReferenceException - myList is null here!
    ViewState["myList"] = myList;
}

您仅在 !IsPostBack 时实例化。按钮单击事件是回传。您需要根据您要完成的工作重新设计您的逻辑。 List<Foo> 中存储了什么?如果您打算重复使用或在多个页面上使用,请考虑将对象放入会话缓存中。

将其设置为 static 对 Null Reference Exception 没有帮助。

您需要了解 Page_Load 活动中的检查 if (!IsPostBack) 并记住 Web 是无状态的

所以在您的第一个页面加载时,您的列表是实例化的。接下来会发生什么是当你点击你的按钮。现在它是 Post 返回,这将导致 !IsPostBack 检查 return false。在这里,人们会认为 List 之前已经实例化过,不需要再次实例化。 但是网络是无状态的,所以在 Page_LoadList 已经丢失了内容,它又被设置为 null

你需要保持你的状态。有多种方法可以做到这一点,我想到了 ViewStateSession 和 cookie。阅读它们并相应地使用它们。

在你的情况下你可以这样做:

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
}

这将恢复 post 上的原始列表。但请记住,会话很昂贵,因为它们是在服务器上按用户维护的。

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

要制作 class Serializable 请参阅:Basic Serialization - MSDN

[Serializable]
class Foo
{
  public int ID { get; set;}
  public string Name {get; set;}
}

然后你可以在上面的代码中使用ViewState代替SessionViewState 的优点是它将在客户端以页面方式进行维护,并且不会像 Session 那样对服务器造成负担。所以你的 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>;
    }
}

对于按钮点击:

protected void btnTeste_Click(object sender, EventArgs e)
{
    myList.Add(new Foo { Id = 0, Name = "Nobody" });
    ViewState["myList"] = myList; //save it back in session
}

您可能会看到:ASP.NET State Management Recommendations