2011-10-24 14 views
0

代入演算子のオーバーロードはC#ではできませんが、デフォルトの演算子をブロックすることは可能ですか?代入演算子のオーバーロードのC#の不足を回避するには

状況:複雑な構造エディタを開発中です。それは、多数のクラスオブジェクトの組み合わせとそれらを一緒にリンクすることを可能にする。

多くのクラスのインスタンス間でこれらのリンクと参照を保存できるようにするには、各インスタンスがすべてのクラスにわたって一意のIDを持つ必要があります。私はそれを処理するIDクラス(コンテナオブジェクトへの参照を含む)を作成しました。 IDが一意であることを確認するために、私はクラスをスタティックlist<idClass> IDRegisterのすべてのインスタンスとスタティックlist<idClass> IDReferenceListのすべてのIDインスタンスへの参照を登録するようにしました。

問題:使用する新しいIDインスタンスを1次割り当てまたは作成する際に、IDRegisterにIDを登録して、オブジェクトへの2つの参照を効率的に作成します。クラスインスタンスの使用中に、IDフィールドを別のクラスフィールド(既存または新規)で上書きするのが簡単になりました。登録されていないオブジェクトの通常の上書きはインスタンスを参照しないままにし、ガベージコレクションはメモリのクリーンアップを処理します。この場合、IDRegisterのインスタンスへの参照(場合によっては複数回IDReferenceList)は、IDインスタンスを有効に保ち、古いインスタンスのコンテナオブジェクトを参照することで、それらもクリーンアップできなくなります。これらはすべて私のライブラリに大きなメモリリークを残してしまいます。

解決策?

私のライブラリのメモリリークを受け入れることができません。私は2つの選択肢があります:C + +に行くか、既定の割り当てがIDインスタンスへの既存の参照を上書きしないようにする方法を見つける。

または3番目のオプションはありますか?

答えて

3

フィールドを読み取り専用にすることができます(オブジェクトの構築時の最初の割り当てを除く)。

これを行うには、2通りの方法があります。最初の最も信頼性の高い方法は、パブリックゲッターとセッターのないreadonlyフィールドを使用することです。その後、idはコンストラクタでのみ設定できます。

private readonly int id; 

public int Id 
{ 
    get 
    { 
     return id; 
    } 
} 

第二はセッターがプライベート行われるプロパティを使用することです:

public int Id { get; private set; } 

これはidは、建設後に変更することができますので、readonlyと全く同じではありません。しかし、セッターはプライベートなので、コードのクライアントが誤って値を変更することはありません。

+0

これは、フィールドを変更する必要がある場合はIDRegisterのアクセスを許可する「インターフェイス」としても実行できますが、他のプログラマは書き込みアクセスを許可しないインターフェイスにのみアクセスできます。 –

+0

ありがとうございますが、私はすでにこれを考えました。私の問題は、クラスインスタンス内での値の割り当てではありません(私はあなたのオプションに同意し、既にそれを持っています)。私の問題は、コンテナクラスのフィールドの割り当てです。 IDClass IDField = new IDClass();その後にIDField = new IDClass()またはIDField = SomeClassInstance.IDFieldが残って元のIDインスタンスが残されています – Leo

+0

@Leo:なぜあなたはそれを読み取り専用にできませんか?おそらく、問題を示すより完全な例がありますか? –

0

まず、IDフィールドを最初の割り当てによってのみ設定される読み取り専用プロパティにすることができます。

第2に、アプリケーションでメモリリークが発生する可能性がある場合は、適切にクリーンアップを実行していないことになります。 GCヒープに割り当てていない場合は、クリーンアップを確実にするデストラクタ(通常はdispose()も必要です)が必要です。これは、回避することが不可能などこかで行われるべきです。私。どこかでIDフィールドを上書きしてメモリリークが起こることを心配している場合、デストラクタは間違ったクラスにあります。

+0

私はデストラクタを持っていて、すべて破棄してください。これは、オブジェクトを生かした状態で登録するため、コンテナ内のIDFieldを上書きしてもオブジェクトへの最後の参照が破棄されないため、デストラクタは呼び出されません。 dispose()は、(IDReferenceListに以前の参照がない限り)元のIDFieldを最初に破棄し、前のステップが成功した場合に新しいIDインスタンスを割り当てていることをユーザが認識していることを前提としています。私はすでに、そのプロセスをカバーするために利用可能な静的関数を持っています。 – Leo

+0

廃棄はオブジェクトを解放しないでください。代わりに、ファイナライザはファイナライザを解放する必要がありますが、ファイナライザを呼び出すと、ファイナライザを終了する必要はありません。 (ファイナライザは、特に指示がない限り、GCによって常に呼び出されます)これは、オブジェクトがマップから落ち、最終的にGCによってクリーンアップされると、管理されていないオブジェクトがまだクリーンアップされるような "セーフティネット"を提供します。 – tylerl

+0

前述のとおり、IDインスタンスは登録リストのためにGCに従ってマップから外れません。リストのリストと知識はライブラリ内部にあります。だから、すべての目的と目的のために、IDインスタンスは、クラスの内部動作の知識を必要とすべきでないユーザのためにマップから外れます。再割り当ての前に明示的な呼び出しを行う必要があり、間違いが起きるように頼んでいます。ユーザがリストを見ることができないので、ライブラリの使用における問題を追跡することは、最高では困難である。 WeakReferenceクラスはちょうど私の問題を解決しました。 – Leo

関連する問題