1

まず、これがばかげた質問である場合はお詫び申し上げます。VB6 以降、何もプログラミングしていないので、C# を 16 時間使用しています。私は、古い Access データベースから読み取り、Excel で書式設定されたレポートを出力する個人用の小さなプログラムを一緒にハックしようとしています。乱雑で非効率的なコードで申し訳ありません。

概要: 「ゾーン」と「デバイス」の 2 つのクラス タイプがあります。各「ゾーン」には、デバイスのリストがあります。メイン プログラムにはゾーンのリストがあります。各データベースにはさまざまな数の「ゾーン」があり、各「ゾーン」にはさまざまな数のデバイスが割り当てられています。ゾーン リストと各ゾーンのデバイスを順番に解析する必要があります。私は構造体と配列から始めましたが、どちらも悪い方法であるというのが一般的な意見のようで、とにかくあまり運がなかったので、リストとクラスに移行しましたが、うまくいきました。

データベースからすべての「ゾーン」を取得し、リストに追加して、ラベルと ID を割り当てることができます。問題は、データベースから「デバイス」を読み取ろうとすると、それらをゾーン内のリストに追加できないことです。

これは、「オブジェクト参照がオブジェクトのインスタンスに設定されていません」というエラーです。オブジェクトがnullであることを意味するのはどれですか?

関連するコードは次のとおりです。

デバイス クラス:

    public class Device
    {
        public string Label;
        public string Address;
        public string Type;
        public Device(string Label, string Address, string Type)
        {
            this.Address = Address;
            this.Label = Label;
            this.Type = Type;
        }
    }

ゾーン クラス:

    public class Zone
    {
        public string Label;
        public short ID;
        public List<Device> Devices;

        public Zone(string Label, short ID) {
            this.Label = Label;
            this.ID = ID;
            // ADDED AS PER SUGGESTIONS BELOW
            this.Devices = new List<Device>();
        }

        // Added this to see if it would work, it would not.
        public void AddDevice(string Label, string Address, string Type) {
            Devices.Add(new Device(Label, Address, Type));
        }            
    }

ゾーン リストの初期化と入力 (ボタン クリック時) (正常に完了)

    List<Classes.Zone> Zones = new List<Classes.Zone>();
    dbZoneReader = myZoneSelect.ExecuteReader();

            while (dbZoneReader.Read())
            {
                Classes.dbItem dbRow = new Classes.dbItem();
                dbRow.Address = Convert.ToInt16(dbZoneReader["DeviceAddress"].ToString());
                dbRow.DeviceType = Convert.ToInt16(dbZoneReader["DeviceType"].ToString());
                dbRow.Label = dbZoneReader["DeviceLabel"].ToString();

                if (dbRow.Label != "" && dbRow.Address > 0)
                {
                    Zones.Add(new Classes.Zone(dbRow.Label,dbRow.Address));                        
                }
            }

それぞれのゾーンへのデバイスの追加:

    while (dbReader.Read()) {  
                Classes.dbItem dbRow = new Classes.dbItem();                    
                string tempZones;

                // Acquire/convert device information
                dbRow.Node = Convert.ToInt16(dbReader["NodeAddress"].ToString());                                     
                dbRow.Loop = Convert.ToInt16(dbReader["LoopSelection"].ToString());                                  
                dbRow.Address = Convert.ToInt16(dbReader["DeviceAddress"].ToString());                                
                dbRow.TypeID = Convert.ToInt16(dbReader["TypeID"].ToString());                                     
                dbRow.FlashScanID = Convert.ToInt16(dbReader["FlashScanID"].ToString());
                dbRow.DeviceType = Convert.ToInt16(dbReader["DeviceType"].ToString());
                dbRow.Label = dbReader["DeviceLabel"].ToString();

                // Find "proper" zone ID (some zones have multiple IDs, only one is relevant)
                tempZones = dbReader["DevicePointMappingList"].ToString();
                tempZones = tempZones.Replace("Z", "");
                var elements = tempZones.Split(new[] { ',' }, System.StringSplitOptions.RemoveEmptyEntries);
                if (elements.Length >= 2) {
                    ZoneCheck z = new ZoneCheck();
                    foreach (string items in elements) { if (z.Check(items))  { dbRow.Zone = Convert.ToInt16(items); } }
                } else {
                    if (elements.Length == 1) { dbRow.Zone = Convert.ToInt16(elements[0]); }
                    else { dbRow.Zone = 0; }
                }

                // Only add devices that aren't assigned to zone 0, which is non-existent
                if (dbRow.Zone > 0)  {   
                    // Add new device to zone's device list [THIS IS WHERE IT FAILS]
                    Zones.Find(z => z.ID == dbRow.Zone).Devices.Add(new Classes.Device("Test", "test", "Test"));                                                     
                }

            }

私はそれがどこで失敗したかを正確に調べて見つけました。それは、デバイスを追加しようとする最後の行です。こことグーグルで検索すると、オブジェクトリストを初期化する必要があると信じるようになりました...私はそれを行ったと思いますか? Zone クラス コンストラクター内で初期化を試みましたが、Zone が追加されたとき (これも現在設定されています)。

Zone オブジェクトが存在すること、およびその Zone オブジェクト内の Detectors リストが null でないことを確認しました。ちょっと困惑して、やってはいけないことをしているのによくわからない、または本当に明白な何かを見逃していると考えてください。

4

3 に答える 3

5

問題はあなたのZoneクラスにあります。次のように初期化する必要がありList<Device>ます。

public class Zone
{
    public string Label;
    public short ID;
    public List<Device> Devices;

    public Zone(string Label, short ID) {
        this.Label = Label;
        this.ID = ID;
        this.Devices = new List<Device>();
    }

    // Added this to see if it would work, it would not.
    public void AddDevice(string Label, string Address, string Type) {
        Devices.Add(new Device(Label, Address, Type));
    }            
}

その理由は、 を書くときpublic List<Device> Devices;、実際にはオブジェクトを作成していないからです。指定されたオブジェクトのインスタンスを保持できる変数を作成しています。= new List<Device>();オブジェクトの使用可能なインスタンスを取得するのは、変数宣言とオブジェクトの初期化 ( ) を組み合わせた場合のみです。

より単純なオブジェクトの観点から同じ問題を考えると、役立つ場合があります。

public class Foo
{
    public string bar; // bar isn't an actual instance of an object, it's just a spot that can hold a string

    public void ManipulateBarWithRuntimeError()
    {
        bar.Substring(0, 1); // "bar" isn't actually set to anything, so how can we take a substring of it? This is going to fail at runtime.
    }

    public void ManipulateBarWithoutRuntimeError()
    {
        bar = "Hello, world!";
        bar.Substring(0, 1); // bar is actually set to a string object containing some text, so now the Substring method will succeed
    }

}
于 2013-07-27T17:37:22.533 に答える