How can I serialize an object that has an interface as a property?

蓝咒 提交于 2019-12-18 22:58:13

问题


I have 2 interfaces IA and IB.

public interface IA
{
    IB InterfaceB { get; set;  }
}

public interface IB
{
    IA InterfaceA { get; set;  }

    void SetIA(IA value);
}

Each interfaces references the other.

I am trying to serialize ClassA as defined below.

[Serializable]
public class ClassA : IA
{
    public IB InterfaceB { get; set; }

    public ClassA()
    {
        // Call outside function to get Interface B
        IB interfaceB = Program.GetInsanceForIB();

        // Set IB to have A
        interfaceB.SetIA(this);
    }
}

[Serializable]
public class ClassB : IB
{
    public IA InterfaceA { get; set; }

    public void SetIA(IA value)
    {
        this.InterfaceA = value as ClassA;
    }
}

I get an error when I try too serialize because the 2 properties are interfaces. I want to serialize the properties.

How would I get around this?

I need to have references in each interface to the other. And I need to be able to serialize the class back and forth.


回答1:


You have various bugs in your code, otherwise this would work just fine.

  1. In the constructor for ClassA, your are setting an local variable IB, not the object's IB object.
  2. In ClassB, you are casting back to the object concrete class, instead of leaving it alone as the interface type.

Here is what your code should look like:

public interface IA 
{ 
    IB InterfaceB { get; set; } 
}

public interface IB 
{ 
    IA InterfaceA { get; set; } 
    void SetIA(IA value);
}

[Serializable]
public class ClassA : IA
{    
    public IB InterfaceB { get; set; }    

    public ClassA()    
    {        
        // Call outside function to get Interface B        
        this.InterfaceB = new ClassB();

        // Set IB to have A        
        InterfaceB.SetIA(this);    
    }
}

[Serializable]
public class ClassB : IB
{    
    public IA InterfaceA { get; set; }    

    public void SetIA(IA value)    
    {       
        this.InterfaceA = value;    
    }
}

[STAThread]
static void Main()
{
    MemoryStream ms = new MemoryStream();
    BinaryFormatter bin = new BinaryFormatter();

    ClassA myA = new ClassA();

    bin.Serialize(ms, myA);

    ms.Position = 0;

    ClassA myOtherA = bin.Deserialize(ms) as ClassA;


    Console.ReadLine();
}



回答2:


Implement ISerializable on your objects to control the serialization.

[Serializable]
public class ClassB : IB, ISerializable
{
  public IA InterfaceA { get; set; }

  public void SetIA(IA value)
  {
     this.InterfaceA = value as ClassA;
  }

  private MyStringData(SerializationInfo si, StreamingContext ctx) {
    Type interfaceAType = System.Type.GetType(si.GetString("InterfaceAType"));
    this.InterfaceA = si.GetValue("InterfaceA", interfaceAType);
  }

  void GetObjectData(SerializationInfo info, StreamingContext ctx) {
    info.AddValue("InterfaceAType", this.InterfaceA.GetType().FullName);
    info.AddValue("InterfaceA", this.InterfaceA);
  }
}



回答3:


Assuming you don't want to serialize the interface property, place the following attribute

[NonSerialized]

on the interface property.




回答4:


In return for your question: two other questions. What do you Serialize? Is the database reference-aware?

You don't serialize interfaces; you serialize objects. The object you serialize is either an implementation of IA or IB.

It's up to the serialized object to decide whether one of it's properties should be serialized or not. If the property does need serializing, it should implement the Serializable interface.

You can only serialize a so called 'island' formed by a circular reference A <-> B if the database can identify the serialized objects: it should first 'allocate' space for A, start serializing A's properties. When it arrives at B, it will find one of it's properties referring to A. The serialization should then include a reference to the serialized version of A.

It's much like two acquaintances moving houses at the same time: first they will exchange their future adresses, only then they will physically move.




回答5:


Interface properties are not serializable. However, fields that reference those properties (in the subclass) are.

You'll need to do something like this:

[Serializable]
public class ClassA : IA
{
    private IB _interfaceB;
    public IB InterfaceB { get { return _interfaceB; } set { _interfaceB = value; } }

    public ClassA()
    {
        // Call outside function to get Interface B
        IB interfaceB = Program.GetInsanceForIB();

        // Set IB to have A
        interfaceB.SetIA(this);
    }
}

[Serializable]
public class ClassB : IB
{
    private IA _interfaceA;
    public IA InterfaceA { get { return _interfaceA; } set { _interfaceA = value; } }

    public void SetIA(IA value)
    {
        this.InterfaceA = value as ClassA;
    }
}


来源:https://stackoverflow.com/questions/821780/how-can-i-serialize-an-object-that-has-an-interface-as-a-property

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!