Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
178 views
in Technique[技术] by (71.8m points)

c# - How to serialize/deserialize an object loaded from another assembly?

I want to serialize/deserialize an object that has been instantiated by another object loaded from an assembly:

Interfaces.cs (from a referenced assembly, Interfaces.dll)

public interface ISomeInterface
{
 ISettings Settings { get; set; }
}

public interface ISettings : ISerializable
{
 DateTime StartDate { get; }
}

SomeClass.cs (from a referenced assembly, 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; }
 }
}

Startup project:

[Serializable]
public class ProgramState
}
 public ISettings Settings { get; set; }
}

In the startup project, eventually I set Settings of an instance of ProgramState to Settings of SomeClass. I then go on to do the serialization using:

public void SerializeState(string filename, ProgramState ps)
{
 Stream s = File.Open(filename, FileMode.Create);
 BinaryFormatter bFormatter = new BinaryFormatter();
 bFormatter.Serialize(s, ps);
 s.Close();
}

This doesn't throw any exceptions. I deserialize with:

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();
}

This throws an exception and the following appears in my Debug output:

A first chance exception of type 'System.Runtime.Serialization.SerializationException' occurred in mscorlib.dll
Unable to find assembly 'SomeClass, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.

I'm sure that the assembly containing SomeClass has been loaded before the call to DeserializeState, so why is it throwing an exception that it is unable to find it?

I've been looking at some tutorials, but the ones I was able to find only deal with classes from the same assembly (plus, my understanding of the serialization and deserialization process in .NET is minimal - a link to a detailed explanation might be helpful).

In the meantime, is there any way to make this correctly deserialize the MySettings object?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

After poking around some more (i.e. googling the answer), I was able to resolve this. Here is the modified code:

Interfaces.cs (from a referenced assembly, Interfaces.dll)

public interface ISomeInterface
{
 ISettings Settings { get; set; }
}

public interface ISettings
{
 DateTime StartDate { get; }
}

SomeClass.cs (from a referenced assembly, 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; }
 }
}

Serialization is done with:

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();
}

And deserialization with:

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();
}

This class was added. This is the binder for the binary formatter:

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;
 }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...