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) 

次にTable、またはTable.Rowsnull です。foreach ループ内からスローされている場合:

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

次に、行の1つがnullであることを意味する可能性が最も高い. どちらを見つけるには、これをループの先頭に追加し、if ステートメント内にブレーク ポイントを配置します。

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

}

デバッグ中に Table.Rows を調べることもできますが、数千行ある場合、これは現実的なオプションではありません。

于 2013-08-05T20:26:57.757 に答える
4

その正確な行に NullReferenceException がある場合、これは、Table変数またはRowsプロパティのいずれかが であることを意味しますnull。他のオプションはほとんどありません。そこにブレークポイントを置き、どれが null かを確認してから、調査して修正してください。

于 2013-08-05T20:26:48.077 に答える
1

null 参照例外をスローすることを想像する唯一の行は、 if Tableisnullです。

foreach (DataRow Row in Table.Rows)

例外がスローされ、行が強調表示されると、デバッガーが表示されます。

デバッガーを使用しているとき、画面の一番下に、Watchまたはというタブが表示されますWatch。そのタブをクリックします。

下部のボックスに単語Tableを入力して Enter キーを押すと、Table I'll bet that's null の値が表示されます。

于 2013-08-05T20:27:34.410 に答える
1

DataTable documentationによると、呼び出しているコンストラクターは、テーブルの名前として使用Stringするオブジェクトを期待しています。実際にはテーブルをロードしません。

DataTable を使用する最善の方法は、DataTable (たとえば、DataTable table = new DataTable()) を初期化してから、Rows プロパティの .Add() メソッドを使用して追加することです。たとえば、mySql クエリの結果を反復処理する foreach ループ内で次のコードを使用できます。

table.Rows.Add(item)

于 2013-08-05T20:34:54.270 に答える
0

これをデバッグして、DataTable が実際に null でないことを確認しましたか?

次は何を返しますか?あなたの問題は、for/each ではなく、そのコード行にある可能性があります

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