2011-01-25 8 views
1

は、彼らがMetaDataKeyと呼ばれるものを持っています。これらは、Wicketコンポーネントに型付きメタ情報を格納するために使用されます。 Wicketのシリアル化を多用しているので、Wicketの設計者は、単純なオブジェクトのアイデンティティが信頼性はないと判断しましたので、各キーのサブクラスを作成することを強制、MetaDataKey抽象クラスを作った後、鍵はサブクラスのインスタンスであるかどうかを確認します(Wicketのソースコードから):なぜオブジェクトを使用するよりも優れたサブタイプの仕事をするだろう、匿名の内部クラスをJavaのキーとして扱いますが、C#ではどのようなものがありますか? Wicketでは

private final static MetaDataKey<String> foo = new MetaDataKey<String>() {}; 

... 

component.setMetaData(foo, "bar"); 

まず:このよう

public boolean equals(Object obj) { 
    return obj != null && getClass().isInstance(obj); 
} 

、私はこのような何かをするだろう、キーとストア何かを作成しますシリアル化の下でのアイデンティティ?

第2に、C#(匿名の内部クラスがない)で同様の機能を作成したいのですが、どうすればいいですか?

+0

クラスが匿名でなければならない理由はありますか?なぜ、通常のC#静的内部クラスは機能しませんか? – Gabe

+0

Gabe: 'class FooKey:MetaDataKeyのようなものです。 {}'? – cdmckay

答えて

2

シリアル化とIDの問題は、シリアル化プロセスが実際に元のオブジェクトのクローンを作成することです。

ObjectInputStream ois = ...; 
SomeThing y = (SomeThing)ois.readObject() 

できないと(それがケースでなければなりませんけれども、そのx.equals(y))あなたが本当にして行きたいと思った場合は

をそのx == yを強制しませんが続く

SomeThing x = ...; 
ObjectOutputStream oos = ...; 
oos.writeObject(x); 

、ほとんどの時間アイデンティティ、あなたが書かれたインスタンス(シングルトンのように)実際には同じストリーム利回りからクラスのインスタンスを読んだことを、強制カスタムシリアル化コードを書く必要があるだろう。これは、権利を取得するのは難しいです、と私は使用するAPIは非常に困難になるだろう魔法の鍵を宣言するために、単純にそれを行うために、開発者を強制的に、と思います。

今日では、一つはenum Sを使用して、シングルトンの文字を強制するためにVMに頼ることができます。

enum MyMetaDataKey implements HyptheticalMetaDataKeyInterface { 

    TITLE(String.class), 
    WIDTH(Integer.class); 

    private final Class<?> type; 

    private MyMetaDataKey(Class<?> t) { type = t; } 
    public Class<?> getType() { return type; } 
} 

欠点は、あなたが、あなたが手動で全体のサポートコードをコーディングする必要がありますので、あなたは、(あなたはそれはしかし、インターフェイスを実装することができます)、共通の基本クラスから継承するENUM宣言することができないこと、であるMetaDataKeyかもしれませんあなたに何度も何度も何度もお世話します。上記の例では、すべてこのgetTypeは抽象基本クラスによって提供されているはずですが、enumを使用していたためできませんでした。

質問の第2の部分について...残念ながら、私はC#でそれに答えて十分に堪能ではありません(すでに言及されているプレーンなプライベートクラスのソリューションに加えて)。

言い換えれば()Ben氏の答えに対するコメントに出てくるを編集してください。同様のことを達成するための1つの解決方法(意味では、Javaソリューションと同じように使用可能です) :

class MyStuff { 
    private static MetaDataKey<String> key = new MetaDataKey<String>(new Guid(), typeof(String)); 
} 

にとして使用することができる

[Serializable] 
public class MetaDataKey<T> { 

    private Guid uniqueId; 
    private Type type; 

    public MetaDataKey(Guid key, Type type) { 
     this.uniqueId; 
     this.type = type; 
    } 

    public override boolean Equals(object other) { 
     return other is MetaDataKey && uniqueId == ((MetaDataKey)other).uniqueId; 
    } 
} 

C#の-languageの違反を無視してください。私はそれを使用してからそれはあまりにも長いです。

これは有効な解決策のようです。しかし、問題はkey定数の初期化にあります。上記の例のように実行すると、アプリケーションが起動されるたびに新しいGuid値が作成され、MyStuffのメタデータ値の識別子として使用されます。たとえば、プログラムの前回の呼び出し(つまり、ファイルに保存されている)からシリアル化されたデータがある場合、別のGuid値MyStuffのメタデータキーを持つキーがあります。デシリアライズ後、効果的に、任意のリクエストは、Guidsが異なるため、失敗します。必要に応じて

class MyStuff { 
    private static Guid keyId = new Guid("{pre-define-xyz}"); 
    private static MetaDataKey<String> key = new MetaDataKey<String>(keyId, typeof(String)); 
} 

今、物事は動作しますが、キーのGUIDを維持する負担はあなたに来ている:だから、例の作業を行うために、あなたは、永続的な事前定義されたGUIDを持っている必要があります。これは、私が思うに、Javaソリューションがこのかわいい匿名サブクラスのトリックで避けようとしていることです。

1

基準アイデンティティを使用してサブタイプを指定する根拠については、あなたと同じくらい暗いです。私が推測しなければならないのは、参照は基本的には派手なポインタであり、その値はシリアライゼーション/デシリアライゼーションによって必ずしも保持されるとは限らず、Javaコンパイラが選んだものと一意のオブジェクトIDをシミュレートする巧妙な方法特定の匿名サブクラスを呼び出す私はJavaの仕様に精通していないので、これが特定の動作か、さまざまなコンパイラの実装の詳細かどうかはわかりません。私はここで完全にオフトラックかもしれません。

C#には匿名型がありますが、System.Object以外のものを継承することはできず、インターフェイスを実装できません。それで、私はこの特定の技術をJavaからどのように移植できるのか分かりません。シリアライズを通じてオブジェクトの一意性を維持して行くために

一つの方法は、thusly行くことができる:Wicketのスタイルのベースクラスは、理論的には、ランタイム・ユニークで、建設に生成されたプライベートメンバーを維持することができ、System.GuidまたはSystem.IntPtrのようなオブジェクトのハンドルの値を取得します。この値は、直列化され、参照平等のためのスタンドとして使用できます。

[Serializable] 
public class MetaDataKey<T> 
{ 
    private Guid id; 

    public MetaDataKey(...) 
    { 
     this.id = Guid.NewGuid(); 
     .... 
    } 

    public override bool Equals(object obj) 
    { 
     var that = obj as MetaDataKey<T>; 
     return that != null && this.id == that.id; 
    } 
} 

EDIT ここでは、オブジェクトの実際の基準値を保存することによってそれを行う方法です。これは少しメモリを消費し、参照平等の概念に若干より真実です。

using System.Runtime.InteropServices; 

[Serializable] 
public class AltDataKey<T> 
{ 
    private long id; // IntPtr is either 32- or 64-bit, so to be safe store as a long. 

    public AltDataKey(...) 
    { 
     var handle = GCHandle.Alloc(this); 
     var ptr = GCHandle.ToIntPtr(handle); 

     id = (long)ptr; 

     handle.Free(); 
    } 

    // as above 
} 
+0

クール、これは私が考えていたものです。私は、これは実際には非常に良いと思うので、ユーザーがキーを作るためにサブクラスを作成するような変なことをする必要はありません。 – cdmckay

+0

Hm。これはほとんどうまくいくかもしれませんが、コンストラクタで新しいGUIDを生成するべきではありません(本質的には、シリアル化された後、クラスの非直列化されたインスタンスはプロセスのライフタイム全体にわたって "マスターキー"しかし、GUIDをコンストラクタに渡すだけで、ソリューションの作業を行うには十分です。 – Dirk

+0

もう一度考えてみてください...固定GUID値が固定されていない限り、私はこのスキームはプロセスの再起動後も生き残ることはできないと思います。 – Dirk

関連する問題