.NET(C#) Serialization , Deserialization

serialization 이란 개체를 저장하거나 전송할 수 있는 형태로 개체의 상태를 변환하는 프로세스 이다. 그리고serialization과 반대로 다시 개체로 변환하는 것을 deserialization이라 한다.

serialization을 사용하는 가장 큰 이유는 개체의 상태를 저장소에 보존 했다가 나중에 똑같은 복사본을 다시 만들거나 한 응용프로그램 에서 다른 응용프로그램으로 개체를 전송하기 위해서 이다.

.NET Framework에서는 제공하는 serialize 방식은 크게 2가지로 나눌 수 있다.

이진 serialization : 형식 정확도를 유지 하므로 응용 프로그램의 여러 호출간에 개체 상태를 유지 하는데 유용하다. 개체를 스트림, 디스크, 메모리, 네트워크 등으로 serialize할 수 있다.

XML serialization : public 속성과 필드만 serialize하며 형식 정확도를 유지하지 않는다. 데이터를 사용하는 응용프로그램을 제한하지 않고 데이터를 제공하거나 사용하려고 할 때 유용하다. XML은 공개 표준이기 때문에 웹을 통해 정보를 공유할 때 적합하고 SOAP도 마찬가지로 공개 표준이다.

형식 정확도를 유지한다는 말은 개체를 serialize을 하고 다시 deserialize했을 때 원본의 개체의 정확한 복제본이 만들어 진다는 것을 의미한다.

이진 serialization

serialize하고자 하는 개체의 public, private필드 와 클래스 이름을 모두 바이트의 스트림 (Binary)로 변환하는 방식이다. 그 후 개체가 deserialize되면 원본 개체의 정확한 복제본이 만들어진다.

이진 serialization에는 3가지 방법이 있다.

기본 serialization

serialize하고자 하는 class를 Serializable특성으로 표시 하는 것으로 해당 클래스의 모든 부분을 serialize한다.


[Serializable]
public class MyObject

{

    public int n1 = 0;

    public int n2 = 0;

    public String str = null;

}

MyObject라는 class를 Serializable 특성으로 표시하였다.

MyObject의 객체를 serialize 하여 파일로 저장하는 예

MyObject obj = new MyObject();

obj.n1 = 1;

obj.n2 = 24;

obj.str = "Some String";

IFormatter formatter = new BinaryFormatter();

Stream stream = new FileStream("MyFile.bin", FileMode.Create, FileAccess.Write, FileShare.None);

formatter.Serialize(stream, obj);

stream.Close();

순서를 요약해보면

1. 인스턴스 생성.

2. BinaryFormatter를 만든다.

3. 파일로 저장하기 위한 FileStream을 만든다.

4. Formatter에게 stream과 개체를 매개 변수로 제공하고 serialize를 지시한다.

5. stream을 닫는다.

이번에는 반대로 serialize된 개체를 반대로 deserialize로 복원 하는 예

IFormatter formatter = new BinaryFormatter();

Stream stream = new FileStream("MyFile.bin", FileMode.Open, FileAccess.Read, FileShare.Read);

MyObject obj = (MyObject)formatter.Deserialize(stream);

stream.Close();

1. BinaryFormatter를 만든다.

2. 저장된 파일을 stream으로 오픈한다.

3. Formatter에게 stream을 제공하고 Deserialize를 지시하고 개체를 받는다.

선택적 serialization

class에서 serialize하지 않아야 하는 필드가 있을 때 해당 멤버변수를 NonSerialized특성으로 표시해 줌으로써 해당 변수가 Serialize되는 것을 방지할 수 있다.

[Serializable]
public class MyObject
{
	public int n1 = 0;

	[NonSerialized]

	public int n2 = 0;

	public String str = null;
}

MyObject클래스의 n2 멤버는 더 이상 serialize되지 않는다.

NonSerialized 특성을 적용했을 때와 적용하지 않았을 때 각각 serialize, deserialize하여 비교해보면 n2멤버의 값이 다름을 확인해 볼 수 있다.

결국 NonSerialized로 표시되지 않은 모든 필드는 serialize된다.

Custom serialization

Custom serialization은 serialization을 직접 제어하는 방식이다. Custom serialization에는 2가지 방법이 있는데

첫번째로는 serialization 도중과 이후에 데이터를 수정하는데 사용되는 메서드에 다음 특성을 적용한다.


OnDeserializedAttribute

OnDeserializingAttribute

OnSerializedAttribute

OnSerializingAttribute

// This is the object that will be serialized and deserialized.
[Serializable()]
public class TestSimpleObject
{
	// This member is serialized and deserialized with no change.
	public int member1;

	// The value of this field is set and reset during and
	// after serialization.
	private string member2;

	// This field is not serialized. The OnDeserializedAttribute
	// is used to set the member value after serialization.
	[NonSerialized()]
	public string member3;

	// This field is set to null, but populated after deserialization.
	private string member4;

	// Constructor for the class.
	public TestSimpleObject()
	{
		member1 = 11;
		member2 = "Hello World!";
		member3 = "This is a nonserialized value";
		member4 = null;
	}

	public void Print()
	{
		Console.WriteLine("member1 = ‘{0}’", member1);
		Console.WriteLine("member2 = ‘{0}’", member2);
		Console.WriteLine("member3 = ‘{0}’", member3);
		Console.WriteLine("member4 = ‘{0}’", member4);
	}

	[OnSerializing()]
	internal void OnSerializingMethod(StreamingContext context)
	{
		member2 = "This value went into the data file during serialization.";
	}

	[OnSerialized()]
	internal void OnSerializedMethod(StreamingContext context)
	{
		member2 = "This value was reset after serialization.";
	}

	[OnDeserializing()]
	internal void OnDeserializingMethod(StreamingContext context)
	{
		member3 = "This value was set during deserialization";
	}

	[OnDeserialized()]
	internal void OnDeserializedMethod(StreamingContext context)
	{
		member4 = "This value was set after deserialization.";
	}
}

각 특성을 적용한 메서드에 원하는 동작을 구현하면 된다.

두번째로는 해당 개체에 ISerializable인터페이스를 구현하면 된다.

ISerializable인터페이스 구현에는 개체가 deserialize될 때 사용되는 특별한 생성자 및 GetObjectData 메서드가 포함되어 있다.

[Serializable]
public class MyObject : ISerializable
{
	public int n1;
	public int n2;
	public String str;

	public MyObject()
	{
	}

	protected MyObject(SerializationInfo info, StreamingContext context)
	{
		n1 = info.GetInt32("i");
		n2 = info.GetInt32("j");
		str = info.GetString("k");
	}
	[SecurityPermissionAttribute(SecurityAction.Demand,
	SerializationFormatter = true)]

	public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
	{
		info.AddValue("i", n1);
		info.AddValue("j", n2);
		info.AddValue("k", str);
	}
}

serialization시에는 구현된 GetObjectData메서드가 호출 되는데 이는 SerializationInfo를 직접 채워야 한다. 이름 및 값 쌍으로 serialize될 변수를 추가하며 모든 텍스트를 이름으로 사용할 수 있다. SerializationInfo에 추가되는 멤버 변수를 자유롭게 결정할 수 있다.

dserialization시에는 직접 SerializationInfo 와 StreamingContext를 받는 특수 생성자를 만들어야한다. 이것이 누락 된 상태에서 deserialize하려고 하면 예외를 trow한다.

XML 및 SOAP Serialization

XML serialization은 개체의 public 필드와 속성 또는 메서드의 매개변수와 반환 값을 XML스트림으로 serialize한다. XML serialization을 사용하면 저장이나 전송을 위해 직렬형식으로 변환되는 public 속성 및 필드가 있는 강력한 형식의 클래스가 만들어 진다.

XML serialization의 특징

XML은 공개 표준이기 때문에 XML 스트림은 플랫폼에 관계없이 필요에 따라 모든 응용 프로그램에서 처리될 수 있다.

XML serialization은 SOAP 사양과 일치하는 XML 스트림으로 개체를 serialize 하는 데 사용할 수도 있다.

개체를 serialize하거나 deserialize하기 위해서는 XmlSerializer클래스를 사용한다.

serialize된 데이터에는 데이터 자체와 클래스의 구조만 포함된다.

public 속성 및 필드만 serialize될 수 있다. 속성에는 public 접근자(get, set)가 있어야 한다. public이 아닌 데이터를 serialize해야 하는 경우 이진 serialization을 사용한다.

class에는 XmlSerializer에 의해 serialize될 기본 생성자가 있어야 한다.

메서드는 serialize될 수 없다.

개체 XML serialize

다음은 개체를 XmlSerializer를 이용하여 serialize한다.

public class MyObject
{
	public int n1 = 0;
	public int n2 = 0;
	private int n3 = 0;
	public String str = null;

	public MyObject()
	{
		n1 = 1;
		n2 = 2;
		n3 = 3;
		str = "Xml Serialization";
	}
}

class Program
{
	static void Main(string[] args)
	{
		MyObject myObject = new MyObject();
		XmlSerializer xmlSerializer = new XmlSerializer(typeof(MyObject));
		StreamWriter writer = new StreamWriter("myObject.xml");
		xmlSerializer.Serialize(writer, myObject);
		writer.Close();
	}
}

1. serialize하고자 하는 인스턴스 생성

2. XmlSerializer를 생성자에 serialize하고자 하는 인스턴스의 타입을 전달하여 생성

3. 기록할 stream생성

4. XmlSerializer에게 stream과 개체를 전달하여 serialize지시

위의 결과 물인 myObject.xml에는 다음과 같은 내용이 있다.



  1
  2
  Xml Serialization

private 멤버와 메서드의 정보는 기록 되지 않는 것을 확인할 수 있다.

개체 XML deserialize

이번에는 myObject.xml을 다시 deserialize해본다.


class Program
{
	static void Main(string[] args)
	{
		XmlSerializer xmlSerializer = new XmlSerializer(typeof(MyObject));
		StreamReader reader = new StreamReader("myObject.xml");
		MyObject myObject = (MyObject) xmlSerializer.Deserialize(reader);

		Console.WriteLine(myObject.n1);
		Console.WriteLine(myObject.n2);
		Console.WriteLine(myObject.str);
	}
}

1. XmlSerializer를 생성자에 deserialize하고자 하는 인스턴스의 타입을 전달 하여 생성

2. stream을 읽어 들이는 reader 생성

3. XmlSerializer에게 stream을 전달하여 deserialize를 지시하고 리턴되는 Object를 복원하고자 하는 타입에 맞게 캐스팅 하여 받아 낸다.

개체를 SOAP 인코딩된 XML 스트림으로 Serialize하기

SOAP 메시지는 XML을 사용하여 생성되므로 XmlSerializer를 사용하여 클래스를 serialize하고 인코딩된 SOAP 메시지를 생성할 수 있다.

SOAP 인코딩된 XML serialize하기 위해서는 기존의 XML serialize에서 XmlSerializer생성자 매개 변수에 serialize하고자 하는 인스턴스의 타입을 전달 했던 것과 달리, 새 SoapReflectionImporter를 만들고 serialize된 클래스의 형식으로 ImportTypeMapping 메서드를 호출하여 XmlTypeMapping을 만든뒤 XmlSerializer생성자 매개 변수에 전달 한다.

class Program
{
	static void Main(string[] args)
	{
		MyObject myObject = new MyObject();

		XmlTypeMapping xmlTypeMapping =
				  new SoapReflectionImporter().ImportTypeMapping(typeof (MyObject));

		XmlSerializer xmlSerializer = new XmlSerializer(xmlTypeMapping);
		StreamWriter writer = new StreamWriter("myObject.xml");
		xmlSerializer.Serialize(writer, myObject);
		writer.Close();
	}
}

기존의 XML serializer에서 XmlSerializer의 생성방식만 변경되었다.

이때 결과물 myObject.xml에는 다음과 같은 내용이 있다.



  1
  2
  Xml Serialization

SOAP형식으로 인코딩된 데이터가 있음을 확인할 수 있다.

One thought on “.NET(C#) Serialization , Deserialization

  1. 애국동맹

    [Serializable] 선언을 하지 않은 클래스를 상속받는 클래스의 경우 [Serializable] 선언을 하더라도 Deserialize시 에러가 발생합니다. 이 문제는 어떻게 해결하면 좋을까요?

답글 남기기

이메일 주소는 공개되지 않습니다.

You may use these HTML tags and attributes:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> 

이 사이트는 스팸을 줄이는 아키스밋을 사용합니다. 댓글이 어떻게 처리되는지 알아보십시오.