Проблема с сериализацией и идентификацией заключается в том, что процесс сериализации фактически создает клон исходного объекта. Большую часть времени,
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
.
Что касается второй части вопроса... К сожалению, я не чувствую себя достаточно опытным в С#, чтобы ответить на этот вопрос (помимо уже упомянутого использования простого решения частного класса, уже приведенного в комментариях).
Тем не менее... (Изменить, чтобы ответить на вопросы, появившиеся в комментариях к ответу Бена) Одно из возможных решений для достижения чего-то подобного (в том смысле, что оно будет столь же полезным, как и решение 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));
}
Теперь все работает, как хотелось бы, но на вас легло бремя поддержки ключевых гидов. Я думаю, это то, чего Java-решение пытается избежать с помощью этого милого трюка с анонимным подклассом.
person
Dirk
schedule
25.01.2011
class FooKey : MetaDataKey<string> { }
? - person cdmckay   schedule 25.01.2011