1

わかりました。C#が値型と参照型をどのように処理するかに関連していると私が信じている本当に厄介な問題がありますが、バグが正確に何であるかはわかりません。

public partial class LogicSimulationViewerForm : Form
    {

    private Dictionary<string, PointStruct> pointValues;


private void SearchPoint(string code)
    {
        ReadDefaultPointValuesResponse result = ddcdao.ReadDefaultPoint(points);
        pointValues = new Dictionary<string, PointStruct>();

        for (int j = 0; j < result.pointidentifier.Length; j++)
        {
            if (!pointValues.ContainsKey(result.pointidentifier[j]))
            {
                PointStruct ps = new PointStruct();
                ps.name = "Random String"; 
                ps.pointidentifier = result.pointidentifier[j];
                ps.outofservice = result.outofservice[j];

                pointValues.Add(result.pointidentifier[j], ps);
                ...

pointValuesは、クラスのプライベートフィールドとして格納されます。同じクラスですが、関数が異なります。次のことを実行しようとすると、次のようになります。

PointStruct ps = pointValues[s];
MessageBox.Show(ps.name);
MessageBox.Show(ps.pointidentifier);
MessageBox.Show(ps.outofservice);

ps.pointidentifierとps.outofserviceは正しく表示されますが、ps.nameは、私が何をしても常にnullとして返されます。この問題を解決するにはどうすればよいですか?

編集:リクエストに応じて、問題をさらに説明するためにコードを追加しています:

public struct PointStruct
{
    public string pointidentifier;
    public string affect;
    public string outofservice;
    public string priorityarray;
    public string pointtype;
    public string alarmstate;
    public string correctvalue;
    public string presentvalue;
    public string name;
    public string test;
}
4

2 に答える 2

3

classブードゥー教 (明示的なフィールド レイアウト、プロパティの間接化など) がない限り、それが であるか であるかに関係なく、フィールドがそれ自体を消去する必要がある理由はまったくありませんstruct

それが だった場合class、おそらくそれはどこか他の場所での不注意な更新に帰することができます。

var foo = pointValues[key];
// snip 2000 lines
foo.name = newValue; // which happens to be null

もちろん、辞書によって参照されるものと同じ基本オブジェクトを更新します。ただし、コピーは個別であるため (配列内で直接更新しない限り)、これはaには適用されません。struct

pointValues.Add(...)ある場所でのみ使用されていると述べていることを考えると、それを引き起こす唯一の方法は、インデクサーを介して他の場所で上書きしていることです。

pointValues[key] = newValueWithANullName;

とはいえ、そうは言っても。非常に具体的な理由がない限りPointStruct、. になる目的はほとんどありませんstruct。それはclass. にとっては非常に「太い」ですstruct。また; ほとんどの場合、structs は不変でなければなりません。

于 2012-07-06T12:43:22.530 に答える
1

Dictionaryに格納された構造体のフィールドのいずれかがstring、構造体が に格納されたときに保持されていた値以外のものを保持するように変更されることは、非常に驚​​くべきことDictionaryです。あなたの名前は実際にリテラル"Random String"ですか、それとも他の関数を表すためにそのリテラルを使用していますか? 問題の機能が実際に動作していることを確認しましたか?

ここにいる一部の人々とは異なり、.net のサポートには制限がありますが、構造体の所有者が誰がそれを変更できるかを制御できるため、私は変更可能な構造体が大好きです。対照的に、可変クラス オブジェクトへの参照が外部コードに公開されたことがある場合、それがいつ、誰によって変更されるかはわかりません。構造体であるということPointStructは、取得する構造体Dictionaryのフィールドの内容が、構造体が格納されたときのフィールドの内容と同じである可能性が 99.44% あることを意味します。チェックを追加して、NameフィールドがDictionaryほぼ確実に問題を見つけることができます。外部コードを調べて、何も変更されていないことを確認する必要がある可変クラスよりも、はるかに良い状況です。

補遺

変更可能な構造体には 1 つの悪い点があります。それは、コンストラクターまたはプロパティ セッター以外の構造体メンバーがあり、それが変化thisする場合、そのようなメンバーを読み取り専用コンテキストで使用しようとすると、偽のコードが生成されますが、そうではありません。コンパイラ診断を生成します。値型のセマンティクスを適切にサポートする言語とフレームワークでは、変更するメンバーにそのようにタグ付けする必要がありthis、読み取り専用コンテキストでそのようなメンバーを使用することを禁止していますが、残念ながら .net にはそのようなタグ付けがありません。コンストラクターとプロパティ セッターが基礎となる構造体を変更し、ゲッターとその他のメソッドは変更しないと単純に推測します。`Name フィールドに構造体メソッドが入力されている場合、たとえば

void ComputeName(void)
{
  名前 = someRandomString();
}

これを静的メソッドに置き換えることを強くお勧めします。

void ComputeName(構造体を参照)
{
  theStruct.Name = someRandomString();
}

前者の関数が の読み取り専用インスタンスで呼び出された場合PointStruct、コンパイラは (前述のように) 問題なくコンパイルしますが、結果のコードは機能しません。ただし、読み取り専用インスタンスをPointStruct後者に渡そうとすると、コンパイラ エラーが発生します。

于 2012-07-10T15:29:20.570 に答える