0

コードが現在のスコープから外れると、既存のオブジェクトに対して何かを実行するラッパーを作成する必要があります。

コードは次のようになります。

public class ObjWrapper : IDisposable
{
   private KnownType dt = null;

   public ObjWrapper(KnownType data)
   {
      this.dt = data;
   }

   public void Dispose()
   {
      SaveKnownTypeInDB(this.dt);
   }
}

呼び出しは次のようになります。

KnownType data = new KnownType();
// do something on `data`

using (ObjWrapper ow = new ObjWrapper(data))
{
  // do something on `data`
}

オブジェクトの元の状態からデータベース内の値を常に取得しています。Dispose() 内にブレークポイントを配置すると、元の値になっていることが確認できます。呼び出し元メソッドのスタックをチェックしているとき、コンストラクターで渡したオブジェクトには正しい値があります。dataオブジェクトが参照渡しされ、内部で呼び出されるすべてのプロパティObjWrapperが「更新された」値を持つことを期待していました。コンストラクターでデータを渡すか、コンストラクターの直後にrefデータをプロパティとして配置して設定することも試みましたが、すべて同じです。ObjWrapper理由はありますか?この種のオブジェクトでは、C#は参照を使用していると思いました...

ありがとう。

更新しました

4

5 に答える 5

2

予想される動作は、Dispose にブレークポイントを設定すると、データの初期状態のみが表示されることです。

KnownTypestructではなくクラスであるため、常に の内部で参照を割り当てています。そのため、加えた変更はラッパー内にも反映されます。ObjWrapperdata

この種のオブジェクトでは、C#は参照を使用していると思いました...

そのため、オブジェクトの現在の状態が表示されます。元のインスタンスへの参照を保存しているため、インスタンスへの変更はその参照にも反映されます。

データのコピーを保存する場合は、自分でコピーを作成する必要があります。これは、値を手動でコピーすることを意味する可能性があります。

于 2012-10-16T16:32:23.573 に答える
1

問題の多くはまだ示していないコードに基づいていますが、知識に基づいた推測を行うには十分です。

KnownTypeそれがクラスであると仮定します。クラスであるため、参照型です。つまり、変数 ( など) には、オブジェクトに含まdataれるデータが実際には含まれていません。変数には、 「別の場所」に存在する実際のオブジェクトKnownTypeの参照 (メモリ内の場所) が含まれます。KnownType

オブジェクトをコンストラクターに渡すときはKnownType、値で渡しますが、その値は単なる参照です。これは、参照のコピーを作成していることを意味します。2 つの参照はどちらも同じ実際のオブジェクトを指しています。このため、両方が指している実際のオブジェクトが変更された場合、両方の変数が変更を「認識」します。ただし、いずれかの変数が指すオブジェクトを変更すると、もう一方の変数はその変更を認識しません。dataしたがって、変更がデータベースに反映されていない場合は、using 内の既存のオブジェクトを変更するのではなく、まったく新しいKnownTypeオブジェクトをその変数に割り当てていることを意味します。(このコードを示していないので、確実に言うのは難しいです。)

したがって、最初の解決策は、do not do thatです。に渡したオブジェクトを変更dataするだけで、何を指すかを変更しないでください。dataObjWrapper

KnownType新しいものを割り当てて、dataその新しいものを保存できることが本当に重要な場合は、次のようにすることができます(意味的に奇妙なので、回避できる場合はお勧めしません、バグが発生しやすくなります。)

public class ObjWrapper : IDisposable
{
    private Func<KnownType> functor;
    public ObjWrapper(Func<KnownType> functor)
    {
        this.functor = functor;
    }
    public void Dispose()
    {
        SaveKnownTypeInDB(functor());
    }
}

そしてそれを使用するには:

KnownType data = new KnownType();
// do something on `data`

using (ObjWrapper ow = new ObjWrapper(() => data))
{
    // do something on `data`
}
于 2012-10-16T21:00:08.047 に答える
0

これが起こった理由を見つけました:

  • オブジェクトの初期状態 (コンストラクターに入る前) は 'new' に近かった (そのメンバーのほとんど、少なくともウォッチ ウィンドウに表示されるメンバーのほとんどは 'default' 値でした)。
  • ラッパーのスコープ内で、オブジェクトはさまざまな関数に渡されました。それらの 1 つは、いくつかのロジックに基づいて、オブジェクトを「再作成」し、そのプロパティに別のオブジェクトのプロパティを設定することにしました。
  • もちろん、これは元のオブジェクトの参照がラッパーのスコープ内で変更されたことを意味します。
  • 外部のラッパー クラスでは、「参照」はまだ古いオブジェクトを「指している」ままでした。

これは、新しい事実に照らして正常であり、予想される動作です。皆さんの助けと提案に感謝します!

于 2012-11-14T22:11:08.480 に答える
0

Reference 型と Value 型の違いを理解する必要があります。オブジェクトのコピーを渡すのではなく、オブジェクトへの参照を渡します。ObjWrapper クラスのコンストラクターでディープ コピー メカニズムを実装/呼び出す必要があると思います。

于 2012-10-16T16:36:30.533 に答える
0

リソースを解放するために Dispose() メソッドを実装することになっています。Dispose() メソッドを明示的に呼び出していない場合は、いつ実行されるかを判断できません。リソースの解放以外のロジックやコードを記述しないことをお勧めします。

于 2012-10-16T16:36:55.577 に答える