1

在这一行foreach (DataRow Row in Table.Rows)中,我得到了 NullReferenceException。

该程序位于 C# 的模拟器中。当我调试它并且它崩溃时,它会foreach以黄色突出显示这个词。我在下面粘贴了我的整个代码。

using System;
using System.Collections.Generic;
using System.Data;

using Reality.Storage;
using System.Threading;

namespace Reality.Game.Moderation
{
    public static class ModerationBanManager
    {
        private static List<uint> mCharacterBlacklist;
        private static List<string> mRemoteAddressBlacklist;
        private static Thread mWorkerThread;
        private static object mSyncRoot;

        public static void Initialize(SqlDatabaseClient MySqlClient)
        {
            mCharacterBlacklist = new List<uint>();
            mRemoteAddressBlacklist = new List<string>();
            mSyncRoot = new object();

            mWorkerThread = new Thread(new ThreadStart(ProcessThread));
            mWorkerThread.Name = "ModerationBanManager";
            mWorkerThread.Priority = ThreadPriority.Lowest;
            mWorkerThread.Start();

            ReloadCache(MySqlClient);
        }

        public static void ProcessThread()
        {
            try
            {
                while (Program.Alive)
                {
                    Thread.Sleep(600000);

                    using (SqlDatabaseClient MySqlClient = SqlDatabaseManager.GetClient())
                    {
                        ReloadCache(MySqlClient);
                    }
                }
            }
            catch (ThreadAbortException) { }
            catch (ThreadInterruptedException) { }
        }

        public static void ReloadCache(SqlDatabaseClient MySqlClient)
        {
            lock (mSyncRoot)
            {
                mCharacterBlacklist.Clear();
                mRemoteAddressBlacklist.Clear();

                MySqlClient.SetParameter("timestamp", UnixTimestamp.GetCurrent());
                DataTable Table = MySqlClient.ExecuteQueryTable("SELECT * FROM bans WHERE timestamp_expire > @timestamp");

                foreach (DataRow Row in Table.Rows)
                {
                    uint UserId = (uint)Row["user_id"];
                    string RemoteAddr = (string)Row["remote_address"];

                    if (UserId > 0 && !mCharacterBlacklist.Contains(UserId))
                    {
                        mCharacterBlacklist.Add(UserId);
                    }

                    if (RemoteAddr.Length > 0 && !mRemoteAddressBlacklist.Contains(RemoteAddr))
                    {
                        mRemoteAddressBlacklist.Add(RemoteAddr);
                    }
                }
            }
        }

        public static bool IsRemoteAddressBlacklisted(string RemoteAddressString)
        {
            lock (mSyncRoot)
            {
                return mRemoteAddressBlacklist.Contains(RemoteAddressString);
            }
        }

        public static bool IsUserIdBlacklisted(uint UserId)
        {
            lock (mSyncRoot)
            {
                return mCharacterBlacklist.Contains(UserId);
            }
        }

        public static void BanUser(SqlDatabaseClient MySqlClient, uint UserId, string MessageText, uint ModeratorId)
        {
            MySqlClient.SetParameter("userid", UserId);
            MySqlClient.SetParameter("reason", MessageText);
            MySqlClient.SetParameter("timestamp", UnixTimestamp.GetCurrent());
            MySqlClient.SetParameter("timestampex", UnixTimestamp.GetCurrent());
            MySqlClient.SetParameter("moderator", ModeratorId);
            MySqlClient.ExecuteNonQuery("INSERT INTO bans (user_id,reason_text,timestamp_created,timestamp_expire,moderator_id) VALUES (@userid,@reason,@timestamp,@timestampex,@moderator)");

            lock (mSyncRoot)
            {
                mCharacterBlacklist.Add(UserId);
            }
        }
    }
}
4

5 回答 5

5

如果它真的被扔在这条线上:

foreach (DataRow Row in Table.Rows) 

那么TableorTable.Rows为空。如果它是从你的 foreach 循环内部抛出的:

foreach (DataRow Row in Table.Rows) 
{
   //aka in here
}

那么它很可能意味着您的行之一为空。要查找哪一个,请在循环的开头添加它并在 if 语句中放置一个断点。

foreach (DataRow Row in Table.Rows) 
{
   if(Row == null)
   {
       //breakpoint here!
   }

}

您也可以在调试时只检查 Table.Rows,但如果有 1000 行,这不是一个现实的选择。

于 2013-08-05T20:26:57.757 回答
4

如果在该行中有 NullReferenceException,这意味着Table变量或Rows属性是null. 几乎没有其他选择。请在此处放置一个断点并检查其中一个为空 - 然后进行调查并更正它。

于 2013-08-05T20:26:48.077 回答
1

根据DataTable 文档,您正在调用的构造函数期望使用一个String对象作为表的名称。它实际上并没有加载表。

使用 DataTable 的最佳方法是初始化您的 DataTable(例如,DataTable table = new DataTable()),然后使用 Rows 属性的 .Add() 方法添加到它。为了说明,您可以在遍历 mySql 查询结果的 foreach 循环中使用以下代码:

table.Rows.Add(item)

于 2013-08-05T20:34:54.270 回答
1

我想抛出空引用异常的唯一一件事是 if Tableis null

foreach (DataRow Row in Table.Rows)

当抛出异常并突出显示该行时,您就在调试器中。

当您在调试器中时,在屏幕的最底部,您会看到一个名为Watchor的选项卡Watch。单击该选项卡。

在底部的框中​​,输入单词Table并按 Enter,它应该会显示Table I'll bet that's null 的值。

于 2013-08-05T20:27:34.410 回答
0

您是否对此进行了调试并确保您的 DataTable 实际上不是空的?

以下返回什么?您的问题可能出在该行代码中,而不是在 for/each 中

DataTable Table = MySqlClient.ExecuteQueryTable("SELECT * FROM bans WHERE timestamp_expire > @timestamp");
于 2013-08-05T20:29:48.530 回答