Как сериализовать/десериализовать объект, загруженный из другой сборки?
Я хочу сериализовать/десериализовать объект, который был создан другим объектом, загруженным из сборки:
Интерфейсы .cs(из ссылочной сборки, Interfaces.dll)
public interface ISomeInterface
{
ISettings Settings { get; set; }
}
public interface ISettings : ISerializable
{
DateTime StartDate { get; }
}
SomeClass.cs(из ссылочной сборки, SomeClass.dll)
public class SomeClass : ISomeInterface
{
private MySettings settings = new Settings();
public ISettings Settings
{
get { return (ISettings)settings; }
set { settings = value as MySettings; }
}
}
[Serializable]
public class MySettings : ISettings
{
private DateTime dt;
public MySettings() { dt = DateTime.Now; }
protected MySettings(SerializationInfo info, StreamingContext context)
{
dt = info.GetDateTime("dt");
}
[SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)]
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("dt", dt);
}
public DateTime StartDate
{
get { return startFrom; }
internal set { startFrom = value; }
}
}
Вводный проект:
[Serializable]
public class ProgramState
}
public ISettings Settings { get; set; }
}
В стартовом проекте, в конце концов, я устанавливаю настройки экземпляра ProgramState в настройках SomeClass. Затем я продолжу сериализацию, используя:
public void SerializeState(string filename, ProgramState ps)
{
Stream s = File.Open(filename, FileMode.Create);
BinaryFormatter bFormatter = new BinaryFormatter();
bFormatter.Serialize(s, ps);
s.Close();
}
Это не исключает никаких исключений. Я deserialize с:
public ProgramState DeserializeState(string filename)
{
if (File.Exists(filename))
{
ProgramState res = new ProgramState();
Stream s = File.Open(filename, FileMode.Open);
BinaryFormatter bFormatter = new BinaryFormatter();
try
{
res = (ProgramState)bFormatter.Deserialize(s);
}
catch (SerializationException se)
{
Debug.WriteLine(se.Message);
}
s.Close();
return res;
}
else return new ProgramState();
}
Это генерирует исключение, и на моем выходе Debug появляется следующее:
В mscorlib.dll произошла первая случайная ошибка типа "System.Runtime.Serialization.SerializationException"
Не удалось найти сборку "SomeClass, Version = 1.0.0.0, Culture = neutral, PublicKeyToken = null".
Я уверен, что сборка, содержащая SomeClass, была загружена до вызова DeserializeState, так почему же она бросает исключение, которое не может найти?
Я изучал некоторые учебные пособия, но те, которые мне удалось найти, касались только классов из одной и той же сборки (плюс, мое понимание процесса сериализации и десериализации в .NET минимально - ссылка на подробный объяснение может быть полезно).
Тем временем, есть ли способ сделать это правильно десериализовать объект MySettings?
Ответы
Ответ 1
После того, как выкарабкались еще несколько (т.е. отыграли ответ), я смог это разрешить. Вот модифицированный код:
Интерфейсы .cs(из ссылочной сборки, Interfaces.dll)
public interface ISomeInterface
{
ISettings Settings { get; set; }
}
public interface ISettings
{
DateTime StartDate { get; }
}
SomeClass.cs(из ссылочной сборки, SomeClass.dll)
public class SomeClass : ISomeInterface
{
private MySettings settings = new Settings();
public ISettings Settings
{
get { return (ISettings)settings; }
set { settings = value as MySettings; }
}
}
[Serializable]
public class MySettings : ISettings
{
private DateTime dt;
public MySettings() { dt = DateTime.Now; }
public DateTime StartDate
{
get { return startFrom; }
internal set { startFrom = value; }
}
}
Сериализация выполняется с помощью:
public void SerializeState(string filename, ProgramState ps)
{
Stream s = File.Open(filename, FileMode.Create);
BinaryFormatter bFormatter = new BinaryFormatter();
bFormatter.AssemblyFormat =
System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple;
bFormatter.Serialize(s, ps);
s.Close();
}
И десериализация с помощью:
public ProgramState DeserializeState(string filename)
{
if (File.Exists(filename))
{
ProgramState res = new ProgramState();
Stream s = File.Open(filename, FileMode.Open);
BinaryFormatter bFormatter = new BinaryFormatter();
bFormatter.AssemblyFormat =
System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple;
bFormatter.Binder = new MyBinder(); // MyBinder class code given below
try
{
res = (ProgramState)bFormatter.Deserialize(s);
}
catch (SerializationException se)
{
Debug.WriteLine(se.Message);
}
s.Close();
return res;
}
else return new ProgramState();
}
Этот класс добавлен. Это связующее средство для бинарного форматирования:
internal sealed class MyBinder : SerializationBinder
{
public override Type BindToType(string assemblyName, string typeName)
{
Type ttd = null;
try
{
string toassname = assemblyName.Split(',')[0];
Assembly[] asmblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (Assembly ass in asmblies)
{
if (ass.FullName.Split(',')[0] == toassname)
{
ttd = ass.GetType(typeName);
break;
}
}
}
catch (System.Exception e)
{
Debug.WriteLine(e.Message);
}
return ttd;
}
}
Ответ 2
Вы хотите (де) сериализовать, используя двоичный формат?
Если нет, вы можете использовать следующее:
P.S. Это не решение, а какое-то обходное решение.
Некоторая сборка
открытый интерфейс ISomeInterface { Настройки ISettings {get; задавать; } }
public interface ISettings : ISerializable
{
DateTime StartDate { get; }
}
public class SerializeHelper<T>
{
public static void Serialize(string path, T item)
{
var serializer = new XmlSerializer(typeof(T));
using (TextWriter textWriter = new StreamWriter(path, false, Encoding.UTF8))
{
serializer.Serialize(textWriter, T item);
}
}
}
SerializeHelper.Serialize(@"%temp%\sample.xml", instanceOfISomeInterface);
Некоторые другие сборки
public interface ISomeOtherInterface
{
ISettings Settings { get; set; }
}
public class DeSerializeHelper<T>
{
public static T Deserialize(string path)
{
T instance = default(T);
var serializer = new XmlSerializer(typeof(TestData));
using (TextReader r = new StreamReader(path, Encoding.UTF8))
{
instance = (T)serializer.Deserialize(r);
}
return instance;
}
}
ISomeOtherInterface instance = DeSerializeHelper.Deserialize<SomeOtherInterfaceImplementation>(@"%temp%\sample.xml")