도입
직렬화는 클래스를 저장하고 불러오기에 편리한 도구지만
많은 프로퍼티와 많은 클래스들을 직렬화(Serialization)하려면
직렬화할 멤버 하나당 2줄의 코드를 쓸 필요가 있습니다
또한 코드를 일일이 쓰다보니 잘못 써서 버그가 생길 염려도 있지요
그렇기에 리플렉션을 이용하여 자동화하는 것이 필요합니다
SerializationHelper
using System;
using System.Linq;
using System.Reflection;
using System.Collections.Generic;
using System.Runtime.Serialization;
namespace CodeGenerater.Example
{
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
public sealed class SerializationTargetAttribute : Attribute
{
}
public static class SerializationHelper
{
public static void Serialize(object Instance, SerializationInfo Info)
{
foreach (dynamic each in GetTarget(Instance))
if (each is FieldInfo)
Info.AddValue(each.Name, each.GetValue(Instance), each.FieldType);
else if (each is PropertyInfo)
Info.AddValue(each.Name, each.GetValue(Instance), each.PropertyType);
}
public static void Deserialize(object Instance, SerializationInfo Info)
{
foreach (dynamic each in GetTarget(Instance))
if (each is FieldInfo)
each.SetValue(Instance, Info.GetValue(each.Name, each.FieldType));
else if (each is PropertyInfo)
each.SetValue(Instance, Info.GetValue(each.Name, each.PropertyType));
}
static IEnumerable<MemberInfo> GetTarget(object Instance)
{
return from q in Instance.GetType().GetMembers(BindingFlags.GetField | BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
where q.GetCustomAttribute<SerializationTargetAttribute>() != null
select q;
}
}
}
| cs |
직렬화를 자동화하기 위한 클래스입니다
Serialize, Deserialize 함수에 있는 dynamic 키워드는 4.0버전부터 가능하므로
만약 그 이전의 버전을 사용하고 계실경우 아래와 같이 쓰시면 됩니다
public static void Serialize(object Instance, SerializationInfo Info)
{
foreach (var each in GetTarget(Instance))
if (each is FieldInfo)
{
FieldInfo F = each as FieldInfo;
Info.AddValue(F.Name, F.GetValue(Instance), F.FieldType);
}
else if (each is PropertyInfo)
{
PropertyInfo P = each as PropertyInfo;
Info.AddValue(P.Name, P.GetValue(Instance), P.PropertyType);
}
}
| cs |
Example
using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
namespace CodeGenerater.Example
{
[Serializable]
class Program : ISerializable
{
#region Serializaion
public void GetObjectData(SerializationInfo Info, StreamingContext Context)
{
SerializationHelper.Serialize(this, Info);
}
Program(SerializationInfo Info, StreamingContext Conmtext)
{
SerializationHelper.Deserialize(this, Info);
}
#endregion
#region Constructor
public Program()
{
}
#endregion
#region Field
[SerializationTarget]
int PrivateField;
#endregion
#region Property
[SerializationTarget]
public int PublicProperty
{
set;
get;
}
[SerializationTarget]
public int HalfPublicProperty
{
private set;
get;
}
[SerializationTarget]
int PrivateProperty
{
set;
get;
}
#endregion
#region Method
static void Main(string[] args)
{
var T = new Program();
int R_PrivateProperty, R_HalfPublicProperty, R_PublicProperty, R_PrivateField;
#region Initialize
Random R = new Random();
T.PrivateProperty = R_PrivateProperty = R.Next();
T.HalfPublicProperty = R_HalfPublicProperty = R.Next();
T.PublicProperty = R_PublicProperty = R.Next();
T.PrivateField = R_PrivateField = R.Next();
#endregion
using (MemoryStream Stream = new MemoryStream())
{
#region Serialization
BinaryFormatter F = new BinaryFormatter();
F.Serialize(Stream, T);
#endregion
#region Init
T = null;
Stream.Position = 0;
#endregion
#region Deserialization
T = (Program)F.Deserialize(Stream);
#endregion
#region Check
bool TestSuccess =
T.PrivateProperty == R_PrivateProperty &&
T.HalfPublicProperty == R_HalfPublicProperty &&
T.PublicProperty == R_PublicProperty &&
T.PrivateField == R_PrivateField;
if (TestSuccess)
Console.WriteLine("Success");
else
Console.WriteLine("Fail");
#endregion
}
}
#endregion
}
}
| cs |
간단하게 작동여부를 확인할 수 있는 예제입니다
주의할 점
프로퍼티를 직렬화할때 Setter와 Getter가 한정자와 상관없이 모두 존재해야합니다
Setter와 Getter 중 하나가 존재하지 않으면 쓰거나 읽을때 오류가 납니다
Archive File