Проблема с сериализацией и идентификацией заключается в том, что процесс сериализации фактически создает клон исходного объекта.Большую часть времени
SomeThing x = ...;
ObjectOutputStream oos = ...;
oos.writeObject(x);
, за которым следует
ObjectInputStream ois = ...;
SomeThing y = (SomeThing)ois.readObject()
, не может и не применяет это x == y
(хотя так и должно быть, что x.equals(y)
)
Если вы действительно хотите использовать идентичность, вам придется написать собственный код сериализации, который обеспечивает, что чтение экземпляра вашего класса из потока дает фактически тот же (как в синглтоне) экземпляр, который был написан.Это трудно понять правильно, и я думаю, что заставление разработчиков сделать это просто для того, чтобы объявить волшебный ключ, сделает API довольно сложным в использовании.
В настоящее время можно использовать enum
s и полагаться на ВМ для принудительного использования одноэлементного символа.
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
.
Что касается второй части вопроса ... К сожалению,Я не чувствую себя достаточно опытным в C #, чтобы ответить на это (помимо уже упомянутого, используйте простое решение частного класса, уже приведенное в комментариях).
Тем не менее ... ( Edit ответить на вопросы, появившиеся в комментариях к ответу Бена) Одно из возможных решений - добиться чего-то похожего (в том смысле, что оно будет столь же полезным, как и решение 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
.Так, если, скажем, у вас есть некоторые сериализованные данные из предыдущего вызова программы (скажем, сохраненные в файле), у нее будут ключи с другим значением Guid, равным ключу метаданных MyStuff
.По сути, после десериализации любой запрос
String myData = magicDeserializedMetaDataMap.Get(MyStuff.key);
не будет выполнен - просто потому, что направляющие отличаются.Таким образом, для того, чтобы пример работал, у вас должны быть постоянные предопределенные Guids:
class MyStuff {
private static Guid keyId = new Guid("{pre-define-xyz}");
private static MetaDataKey<String> key = new MetaDataKey<String>(keyId, typeof(String));
}
Теперь все работает так, как вам нужно, но бремя поддержания ключевых Guides обрушилось на вас.Я думаю, именно этого Java-решение пытается избежать с помощью этой милой анонимной уловки подкласса.