MVC5 / C# - 无法对空引用执行运行时绑定

时间:2016-11-10 15:43:00

标签: c# exception asp.net-mvc-5 runtime-error nullreferenceexception

我试图找出导致此代码出现Cannot perform runtime binding on a null reference错误的原因:

var query = "SELECT Id, UserName, List_Order, LoggedIn " + 
            "FROM AspNetUsers" +
            "WHERE LoggedIn = 1" + 
            "ORDER BY List_Order ASC";

var conn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString);
var cmd = new SqlCommand(query, conn);   
conn.Open();
var rdr = cmd.ExecuteReader();
var n = 0;
while(rdr.Read())
{
    if (Convert.ToString(rdr["UserName"]) != null)
    {
        ViewBag.speakers[n] = new string[4] {
            Convert.ToString(rdr["Id"]),
            Convert.ToString(rdr["UserName"]),
            Convert.ToString(rdr["List_Order"]),
            Convert.ToString(rdr["LoggedIn"]) 
        };

        //Exception Details: Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: Cannot 
        //perform runtime binding on a null reference
        n++;
    }
}

n++增量似乎是导致此错误的原因,我不明白为什么。

更新了代码以反映可能的解决方案。但是,错误仍然存​​在。

尝试使用相同的结果:

if (!string.IsNullOrWhiteSpace(Convert.ToString(rdr["UserName"]))) {
        List<string> speakers = new List<string>();
        speakers.Add(Convert.ToString(rdr["Id"]));
        speakers.Add(Convert.ToString(rdr["UserName"]));
        speakers.Add(Convert.ToString(rdr["List_Order"]));
        speakers.Add(Convert.ToString(rdr["LoggedIn"]));

        ViewBag.speakers[n] = speakers;
        n++;
}

4 个答案:

答案 0 :(得分:2)

对空列值调用.ToString()方法可能会产生Cannot perform runtime binding on a null reference。请改用Convert.ToString();如果您尝试转换null值并且不需要额外的null检查代码,它将返回空字符串。

答案 1 :(得分:2)

您的代码中存在两个问题:

考虑一下:

public ActionResult Index()
{
   int n = 0;
   ViewBag.speakers[n] = 5;
   return View();
}

这段简化的代码抛出Cannot perform runtime binding on a null reference,因为未定义扬声器(空引用)。

您可以通过在循环之前在动态 ViewBag中定义speakers来解决此问题:

ViewBag.speakers = new List<string>();

第二个问题:

ViewBag.speakers[n] = speakers;
您的代码中的发言人是一个列表,您可能希望将ViewBag.speakers定义为List<List<string>>并调用.Add(speakers)而不是使用索引进行访问(您可能会得到 index is超出范围

答案 2 :(得分:1)

ViewBag是一个动态对象,当您尝试对其属性进行赋值时,将在运行时进行空检查。您收到此错误是因为ViewBag.speakers为null,或者它在尝试使用索引器访问其nth广告位时引发异常(可能其大小小于n,或者它没有&#39} ; t根本定义索引器)。您应该在向其添加元素之前初始化ViewBag.speakers

var query = "SELECT Id, UserName, List_Order, LoggedIn " + 
            "FROM AspNetUsers" +
            "WHERE LoggedIn = 1" + 
            "ORDER BY List_Order ASC";

var conn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString);
var cmd = new SqlCommand(query, conn);   
conn.Open();
var rdr = cmd.ExecuteReader();
ViewBag.speakers = new List<string[]>();
while(rdr.Read())
{
    if (Convert.ToString(rdr["UserName"]) != null)
    {
        var speakers = new string[4] {
            Convert.ToString(rdr["Id"]),
            Convert.ToString(rdr["UserName"]),
            Convert.ToString(rdr["List_Order"]),
            Convert.ToString(rdr["LoggedIn"]) 
        };
        ViewBag.speakers.Add(speakers);
    }
}

答案 3 :(得分:0)

您的问题似乎源于在Read之后使用ExecuteReader方法,它在某些点上对动态对象ViewBag.speakers提供了空引用,足以在视图端抛出运行时绑定异常。 / p>

使用DataTable.Load和简单的for循环来迭代DataTable内容,我修改了GökhanKurt对此问题的回答:

var query = "SELECT Id, UserName, List_Order, LoggedIn " + 
            "FROM AspNetUsers" +
            "WHERE LoggedIn = 1" + 
            "ORDER BY List_Order ASC";

using (var conn = new SqlConnection(ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString))
{
    using (var cmd = new SqlCommand(query, conn))
    {
        conn.Open();
        var dt = new DataTable();
        ViewBag.speakers = new List<string[]>();
        var rdr = cmd.ExecuteReader();
        dt.Load(rdr);

        for (int n = 0; n < dt.Rows.Count; n++)
        {
            if (!String.IsNullOrWhiteSpace(Convert.ToString(dt.Rows[n]["UserName"])))
            {
                // speakers returns String[4] array instead of null value
                var speakers = new String[4] {
                    Convert.ToString(dt.Rows[n]["Id"]),
                    Convert.ToString(dt.Rows[n]["UserName"]),
                    Convert.ToString(dt.Rows[n]["List_Order"]),
                    Convert.ToString(dt.Rows[n]["LoggedIn"])
                };

                ViewBag.speakers.Add(speakers);
            }
        }

        conn.Close();
    }
}

注意:SqlDataReader.Read()仅向前,在最后一行到达后将返回false。如果ViewBag.speakers方法返回false,则DataReader.Read分配给空引用,因此while循环不执行。即使DataTable.Load关闭或到达最后一行,使用ExecuteReader方法也会保留SqlDataReader的返回数据。

其次,您可能会看reader.Read() only read once even when there are multiple rows to read问题,但恕我直言,它似乎只有在行长度已知或固定大小时才有效。由于在数据阅读器关闭之前无法使用SqlDataReader.RecordsAffected,因此您需要另一种方法从SqlDataReader获取行数。

参考文献:

Populate data table from data reader

SqlDataReader.Read()

SqlDataReader.RecordsAffected

DataTable.Load()