3

まず、私のソリューションの一部として、という名前で 2 つのプロジェクトがComponentsありWindowsFormsApplication5ます (他にもありますが、それらは関係ありません)。私が参照している辞書はComponents、次のように定義され、そのプロパティとともにあります -

 Dictionary<int, ButtonBase> RespMCQ, DispMCQ; //<Question Number, Checkbox/Radiobutton>
 Dictionary<int, List<ButtonBase>> RespMSQ, DispMSQ;
 public Dictionary<int, ButtonBase> MCQResp
 {
     get
     {
         return RespMCQ;
     }
     set
     {
         RespMCQ = value;
     }
 }
 public Dictionary<int, List<ButtonBase>> MSQResponse
 {
     get
     {
         return RespMSQ;
     }
     set
     {
         RespMSQ = value;
     }
 }
 public Dictionary<int, ButtonBase> MCQDisplay
 {
     get
     {
         return DispMCQ;
     }
     set
     {
         DispMCQ = value;
     }
 }
 public Dictionary<int, List<ButtonBase>> MSQDisplay
 {
     get
     {
         return DispMSQ;
     }
     set
     {
         DispMSQ = value;
     }
 }

QuestionDisplay.cs辞書は、プロジェクトの一部であるのコンストラクターでインスタンス化されます (ここに辞書がComponents存在します)。これは次のように示されます -:

public QuestionDisplay()
{
    InitializeComponent();
    RespMCQ = new Dictionary<int, ButtonBase>();
    DispMCQ = new Dictionary<int, ButtonBase>();
    RespMSQ = new Dictionary<int, List<ButtonBase>>();
    DispMSQ = new Dictionary<int, List<ButtonBase>>();
    ....
}

Form1.csof (私はこの名前を選択しませんでした。WindowsFormsApplication5当たり障りのないように聞こえる場合はご容赦ください) で、私が言及したプロパティを使用しています。名前空間の問題はなく、コンパイルは通常どおり行われます。

Form_Loadただし、 of の実行中Form1にこれらのプロパティを参照すると、次のようなNullReferenceExceptionことわざがスローされます。

Object reference not set to an instance of an object.

これらのプロパティの最初の出現はWorkFlowPanel(string S, QuestionContainerState obj)、フォームのロード時に呼び出されるメソッドにあります -:

 if (QuesTypes[i].Equals("MCQ"))
 {
    string text = "";
    for (int ansCount = 0; ansCount < questions[i].Options.Count(); ansCount++)
    {
        if (Convert.ToInt32(K.Key).Equals(ansCount + 1))
        {
            text = questions[i].Options[ansCount];
            break;
        }
    }
    questionDisplay1.MCQResp.Add(i, new CustomRadio { optionId = Convert.ToInt32(K.Key), Checked = true, Text = text }); //Using anonymous class
 }
 else if (QuesTypes[i].Equals("MSQ") || QuesTypes[i].Equals("Linked"))
 {
     var storeoptions = K.Key.Split(':');
     questionDisplay1.MSQResponse.Add(i, new List<ButtonBase>());
     for (int s = 0; s < storeoptions.Count(); s++)
     {
         questionDisplay1.MSQResponse[i].Add(new CustomChecks { optionId = Convert.ToInt32(storeoptions[s]), Checked = true, Text = questions[i].Options[Convert.ToInt32(storeoptions[s])] });
     }
 }

驚いたことに、デバッグ中に、辞書がインスタンス化されているにもかかわらず、プロパティが常に null であることがわかりました。さて、この問題にはちょっとした歴史があり、文脈を提供するために掘り下げなければなりません。

Could not find a type for a name. The type was System.Collections.Dictionary...私は以前、で発生していたバグと戦っていましたForm1.resx(エラー全体を思い出すことはできません)。どうやら、次のように、辞書のプロパティがバイナリ形式にシリアル化され、resx ファイルで base64 としてエンコードされていたようです。

<data name="MCQDisplay" mimetype="application/x-microsoft.net.object.binary.base64">
<value>
        AAEAAAD/////AQAAAAAAAAAEAQAA....
</value>
<data name="MSQDisplay" .....>
....
....

Stackoverflow で見つけた解決策に従い、コードを古いバージョンにコピーするように指示されました。これは私がそれ以来適用していた修正です。これらのエントリを削除すると (コンパイラ エラーで削除するように求められました)、辞書のプロパティは常に null になることがわかりました。これは私の現在のシナリオに結びついていると感じています。コピーバック操作中に、resx ファイルのエントリが何らかの形で消えてしまったことがありました。

それ以来、このコンパイラ エラーがスローされることはありません。ResXResourceWriterを使用してエントリを再生成するなど、すべてを試しました。それらは認識されていないようで、エラーの代わりに、実行時に辞書のプロパティが常に null であると言われます! IRC の 1 人は、それ自体はButtonBaseシリアライズ可能であるにもかかわらず、シリアライズ可能ではないためにエラーが発生していたことを示唆しています。Dictionary辞書をシリアライズするようにコンパイラーに要求したことはありません。なぜそれが起こったのだろうか。

誰かがこの厄介なバグを解決するのを手伝ってくれたら本当に感謝しています. ButtonBaseまた、子を値として格納する代わりに、子の text、optionId、checked プロパティをミラーリングするプロパティを持つクラス オブジェクトを格納するという漠然とした解決策も頭の中にありましたButtonBase。ただし、これは最後の手段として考えています。

EDIT_1 : これが関連しているかどうかはわかりませんが、次のエントリを見つけましたForm1.Designer.cs-:

this.questionDisplay1.MCQDisplay = ((System.Collections.Generic.Dictionary<int, System.Windows.Forms.ButtonBase>)(resources.GetObject("questionDisplay1.MCQDisplay")));
this.questionDisplay1.MCQResp = ((System.Collections.Generic.Dictionary<int, System.Windows.Forms.ButtonBase>)(resources.GetObject("questionDisplay1.MCQResp")));
this.questionDisplay1.MSQDisplay = ((System.Collections.Generic.Dictionary<int, System.Collections.Generic.List<System.Windows.Forms.ButtonBase>>)(resources.GetObject("questionDisplay1.MSQDisplay")));
this.questionDisplay1.MSQResponse = ((System.Collections.Generic.Dictionary<int, System.Collections.Generic.List<System.Windows.Forms.ButtonBase>>)(resources.GetObject("questionDisplay1.MSQResponse")));

これらを削除するか、何らかの方法で変更する必要がありますか? これらはマシューの答えに何らかの形で関連していると思います。

EDIT_2:次を適用することで、この問題を解決できました-:

  1. マシュー ワトソンの非シリアル化の修正 - コンパイラがディクショナリ プロパティを再度シリアル化しようとした場合。
  2. 上記の のエントリをコメントアウトしましたForm1.Designer.cs

非シリアル化の修正が関連していると感じているため、マシューの回答を受け入れています。

4

1 に答える 1

1

Formこれらのプロパティはパブリックであり、UserControlまたはから派生したクラスのメンバーControlですか?

その場合、フォーム デザイナーがプロパティをフォームの Designer.cs ファイルにシリアル化しようとしている可能性があります。(実際、あなたの言ったことから、それは完全に可能性が高いです。)

DesignerSerializationVisibilityAttributeそれが起こらないようにするには、 を使用してそれを防ぐことができます。次に例を示します。

[
    Browsable(false),
    DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
]

public MyType MyPropertyWhichMustNotBeSerialized
{
    get;
    set;
}

ただし、「.Designer.cs」ファイルに既に配置されている悪いものを編集する必要があります。この属性を追加しても、自動的に削除されない場合があります。

この属性を追加する必要があるかどうかを定期的に確認していない場合は、から直接または間接的に派生したクラスのすべてControlのパブリック プロパティを確認し、必要に応じてこの属性を追加することをお勧めします。


問題は null 参照です。FormLoad()への呼び出しの副作用として呼び出されている可能性はありInitialiseComponent()ますか? これにより、null 参照エラーが発生します。

最も安全にするには、自動プロパティの代わりにバッキング フィールドをプロパティに使用する必要があります。

次に、コンストラクターでフィールドを初期化する代わりに、次のように、フィールドを宣言した場所で初期化します。

private Dictionary<int, ButtonBase>       respMCQ = new Dictionary<int, ButtonBase>();
private Dictionary<int, ButtonBase>       dispMCQ = new Dictionary<int, ButtonBase>();
private Dictionary<int, List<ButtonBase>> respMSQ = new Dictionary<int, List<ButtonBase>>();
private Dictionary<int, List<ButtonBase>> dispMSQ = new Dictionary<int, List<ButtonBase>>();

そうすれば、コンストラクターが呼び出される前に初期化されることが保証されます。

于 2013-05-25T14:36:11.190 に答える