【问题标题】:MVC5 / C# - Cannot perform runtime binding on a null referenceMVC5 / C# - 无法对空引用执行运行时绑定
【发布时间】:2016-11-10 15:43:00
【问题描述】:

我试图从这段代码中找出导致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++;
}

【问题讨论】:

  • @LuisLavieri 我更新了代码,仍然出现错误。
  • 您是否也更新了if?现在应该是:if(!string.IsNullOrWhiteSpace(Convert.ToString(rdr["UserName"])))
  • @LuisLavieri 是的,我确实把它改成了那样,但没有改变。
  • 我看到您正在尝试以数组形式访问 ViewBag。从另一个帖子尝试this answer

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


【解决方案1】:

您的代码中有两个问题:

考虑一下:

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&lt;List&lt;string&gt;&gt; 并调用 .Add(speakers) 而不是使用索引访问(您可能会得到 索引超出范围)

【讨论】:

    【解决方案2】:

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

    【讨论】:

    • 这是一个好记的技巧。我会全力以赴 potentiallyNull?.ToString() ?? string.Empty
    • 我尝试了Convert.ToString 方法,但仍然遇到同样的错误。
    • @Daniel 你已经在某个地方实例化了speakers 吗?
    • @Daniel 抱歉 - 我刚刚看到您发布的以下示例。
    【解决方案3】:

    ViewBag 是一个动态对象,当您尝试对其属性进行赋值时,将在运行时进行空检查。您收到此错误是因为ViewBag.speakers 要么为空,要么在尝试使用索引器访问其nth 插槽时抛出异常(可能它的大小小于n,或者它根本没有定义索引器) .你应该在添加元素之前初始化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);
        }
    }
    

    【讨论】:

      【解决方案4】:

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

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

      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。如果DataReader.Read 方法返回false,则ViewBag.speakers 分配给空引用,因此不会执行while 循环。即使在SqlDataReader 关闭或到达最后一行之后,使用DataTable.Load 方法也会保留来自ExecuteReader 的返回数据。

      其次,您可能会查看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()

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-02-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多