シリアライゼーションと同一性の問題は、シリアライゼーション プロセスが元のオブジェクトのクローンを実際に作成することです。ほとんどの時間、
SomeThing x = ...;
ObjectOutputStream oos = ...;
oos.writeObject(x);
に続く
ObjectInputStream ois = ...;
SomeThing y = (SomeThing)ois.readObject()
それを強制することはできませんし、強制しませんx == y
(そうあるべきですがx.equals(y)
)
本当にIDを使用したい場合は、ストリームからクラスのインスタンスを読み取ると、書き込まれたのと同じ(シングルトンの場合と同じ)インスタンスが実際に生成されるようにするカスタムシリアル化コードを作成する必要があります。これを正しく行うのは難しく、開発者に単純にマジック キーを宣言するように強制すると、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; }
}
欠点は、共通の基本クラスから継承する列挙型を宣言できないことです (ただし、インターフェイスを実装することはできます)。そのため、MetaDataKey
提供される可能性のあるサポート コード全体を何度も何度も手動でコーディングする必要があります。 . 上記の例では、これらすべてgetType
が抽象基本クラスによって提供されているはずですが、 を使用したため提供できませんでしたenum
。
質問の2番目の部分については...残念ながら、私はそれに答えるのに十分なC#に習熟しているとは感じていません(すでにコメントに記載されているプレーンなプライベートクラスソリューションを使用する以外に)。
そうは言っても...(編集して、ベンの回答に対するコメントに表示された質問に回答します)同様のことを達成するための1つの可能な解決策(Javaソリューションと同じくらい使用できるという意味で):
[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;
}
}
次のように使用できます
class MyStuff {
private static MetaDataKey<String> key = new MetaDataKey<String>(new Guid(), typeof(String));
}
C# 言語の違反は無視してください。使ってから時間が経ちました。
これは有効な解決策のように見えるかもしれません。ただし、問題はkey
定数の初期化にあります。上記の例のように実行すると、アプリケーションが開始されるたびに新しい Guid 値が作成され、MyStuff
のメタデータ値の識別子として使用されます。したがって、たとえば、プログラムの以前の呼び出しからシリアル化されたデータがある場合 (たとえば、ファイルに保存されている場合)、MyStuff
のメタデータ キーの異なる Guid 値を持つキーがあります。事実上、逆シリアル化後、すべてのリクエスト
String myData = magicDeserializedMetaDataMap.Get(MyStuff.key);
Guid が異なるという理由だけで失敗します。したがって、この例を機能させるには、永続的な定義済みの Guid が必要です。
class MyStuff {
private static Guid keyId = new Guid("{pre-define-xyz}");
private static MetaDataKey<String> key = new MetaDataKey<String>(keyId, typeof(String));
}
現在、物事は思い通りに機能していますが、主要なガイドを維持する負担があなたにかかっています。これは、Java ソリューションがこのかわいい匿名サブクラスのトリックで回避しようとしているものだと思います。