2016-06-21 1 views
4

C# 직렬화 프레임 워크를 사용하여 참조 픽스 업 (사후 처리)을 수행하는 방법은 무엇입니까?C에서 직렬화 복원 중 참조 픽스 업을 수행하는 방법 #?

다른 개체를 참조하는 개체가있는 개체 그래프가 있습니다. 그들은 모두 ISerializable 인터페이스를 구현하며 모두 인스턴스 ID를 가지므로 직렬화 된 상태로 참조를 나타내는 것은 쉽습니다.

krux는 deserialization 생성자가 호출 될 때 해당 객체가 참조하는 모든 객체가 직렬화되지 않았을 수 있으므로 참조를 유효한 객체로 설정할 수 없습니다. 그리고 참조 픽스 업을 수행하기 위해 C# 직렬화 프레임 워크에서 사후 처리 단계에 연결하는 방법을 찾을 수 없습니다. 그것을 할 수있는 방법이 있습니까?


요청에 따라 여기에 문제가 강조된 고풍스러운 수업이 있습니다.

[Serializable] 
public class Pony : ISerializable 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public Pony BFF { get; set; } 

    public Pony() {} 
    private Pony(SerializationInfo info, StreamingContext context) { 
    Id = info.GetInt32("id"); 
    Name = info.GetString("name"); 
    var bffId = info.GetInt32("BFFId"); 
    BFF = null; // <===== Fixup! Find Pony instance with id == bffId 
    } 

    public void GetObjectData(SerializationInfo info, StreamingContext ontext) { 
    info.AddValue("id", Id); 
    info.AddValue("name", Name); 
    info.AddValue("BFFId", BFF.Id); 
    } 
} 

그리고 여기이 (비) 직렬화 코드 :

var rd = new Pony { Id = 1, Name = "Rainbow Dash" }; 
var fs = new Pony { Id = 2, Name = "Fluttershy", BFF = rd }; 
rd.BFF = fs; 
var ponies = new List<Pony>{ rd, fs }; 
Stream stream = new MemoryStream(); 
var formatter = new BinaryFormatter(); 
formatter.Serialize(stream, ponies); 
stream.Seek(0, SeekOrigin.Begin); 
var deserializedPonies = (List<Pony>)formatter.Deserialize(stream); 

이 질문은 내 문제가 해결되지 않습니다 .net XML Serialization - Storing Reference instead of Object Copy

가 나는 경우 BinaryFormatter +를 ISerializable을 사용하고 싶습니다 직렬화를위한 프레임 워크이며 XmlFormater로 전환하지 않습니다.

+0

어떻게 코드 모양은 필요 같은 직렬화 복원시에 ID를 해결하기 위해 무엇입니까? –

+0

http://stackoverflow.com/questions/1617528/net-xml-serialization-storing-reference-instead-of-object-copy 이미 확인 했습니까? – Fruchtzwerg

+0

기존 코드/기존 코드 용입니까? 그렇지 않다면 XML을 사용하기 위해'XmlSerializer'를 살펴볼 것입니다. 이것은 사용하기가 훨씬 쉬우 며'ISerializer' 인터페이스와'XmlFormatter'를 사용하는 것보다 훨씬 적은 코드가 필요합니다. – Igor

답변

1

이 목적을위한 속성이 있습니다.

는 직렬화하는 모든 개체에서 다음 메소드를 구현 :

[OnDeserialized] 
internal void OnDeserializedMethod(StreamingContext context) { 

} 

당신을 도울 수있는 System.Runtime.Serialization에서 좀 더 속성이 있습니다.

[Serializable] 
    public class Pony { 
    public int Id { 
     get; set; 
    } 
    public string Name { 
     get; set; 
    } 
    public Pony BFF { 
     get; set; 
    } 

    public Pony() { 
    } 

    [OnDeserialized] 
    internal void OnDeserializedMethod(StreamingContext context) { 
     Console.WriteLine(this.Id + " " + this.Name + " " + this.BFF?.Name); 
    } 
    } 

TestMethod :

편집이

난 당신의 코드를 약간 수정 한

var rd = new Pony { Id = 1, Name = "Rainbow Dash" }; 
     var fs = new Pony { Id = 2, Name = "Fluttershy", BFF = rd }; 
     rd.BFF = fs; 
     var ponies = new List<Pony> { rd, fs }; 

     object returnValue; 
     using (var memoryStream = new MemoryStream()) { 
     var binaryFormatter = new BinaryFormatter(); 
     binaryFormatter.Serialize(memoryStream, ponies); 
     memoryStream.Position = 0; 
     returnValue = binaryFormatter.Deserialize(memoryStream); 
     } 
     var xx = (List<Pony>)returnValue; 

당신이 볼 수 있듯이을, 나는 ISerializable 인터페이스, 민간 생성자 및 제거 GetObjectData - 방법.

나는 당신이 정말로 당신이 말한 것처럼 그것을 필요로하지 않는다고 생각했기 때문에 나는 그것을했다. 당신은 (De) Serialization을 구현했다.

접근 한 (전체 직렬화 및 직렬화) ...

private Pony(SerializationInfo info, StreamingContext context) { 

     foreach (SerializationEntry entry in info) { 
     switch (entry.Name) { 
      case "Id": 
      this.Id = (int)entry.Value; 
      break; 
      case "Name": 
      this.Name = (string)entry.Value; 
      break; 
      case "BFF": 
      this.BFF = (Pony)entry.Value; 
      break; 
     } 
     } 
    } 

    public void GetObjectData(SerializationInfo info, StreamingContext ontext) { 
     info.AddValue("Id", Id); 
     info.AddValue("Name", Name); 
     info.AddValue("BFF", BFF); 
    } 
    } 

:

This 후 정보

편집 2의 다른 소스 (Testmethod은 동일하게 유지)입니다. ..

접근법 2 (재귀 객체 - 아이디 만 해당) :

...

private Pony(SerializationInfo info, StreamingContext context) { 

     foreach (SerializationEntry entry in info) { 
     switch (entry.Name) { 
      case "Id": 
      this.Id = (int)entry.Value; 
      break; 
      case "Name": 
      this.Name = (string)entry.Value; 
      break; 
      case "BFF.Id": 
      var bffId = (int)entry.Value; 
      this.BFF = GetPonyById(bffId); // You have to implement this 
      break; 
     } 
     } 
    } 

    public void GetObjectData(SerializationInfo info, StreamingContext ontext) { 
     info.AddValue("Id", Id); 
     info.AddValue("Name", Name); 
     info.AddValue("BFF.Id", BFF.Id); 
    } 

...

+0

어떻게 도움이됩니까? 개체의 모든 * (이 예제의 모든 조랑말)이이 개체뿐만 아니라 deserialize 된 후에 메서드를 실행해야합니다. – Anders

+0

당신은이 방법을 당신의'포니 (pony) '클래스로 구현하려 했습니까? 네가 원한다면 정확히 무엇을하고 싶은지 알 것입니다. – lokusking

+0

예. 두 번 호출됩니다. 각 조랑말 한 번. 동일한 객체에 대한 직렬화 생성자보다 먼저 실행됩니다. 나는. Pony 객체가 생성 된 후 실행되지 않고 BFF 속성 포인터를 수정하는 데 사용할 수 없습니다. – Anders

관련 문제