#nullable enable using System; using System.IO; using System.Runtime.Serialization.Formatters.Binary; namespace UVC.Extension { /// /// 직렬화 관련 확장 메서드를 제공하는 클래스입니다. /// public static class SerializableEx { /// /// 객체의 깊은 복사본을 생성합니다. /// /// 복사할 객체의 타입 (Serializable 속성이 필요) /// 복사할 원본 객체 /// 원본 객체의 깊은 복사본 또는 직렬화 불가능한 경우 기본값 /// /// 이 메서드는 BinaryFormatter를 사용하여 객체를 깊은 복사합니다. /// 대상 타입은 반드시 [Serializable] 속성을 가져야 합니다. /// /// /// /// [Serializable] /// public class Person /// { /// public string Name { get; set; } /// public int Age { get; set; } /// } /// /// // 사용 예시 /// var original = new Person { Name = "홍길동", Age = 30 }; /// var copy = original.DeepCopy(); /// /// // copy는 original과 동일한 값을 가지지만 서로 다른 메모리 참조 /// copy.Name = "김철수"; // original.Name은 여전히 "홍길동" /// /// public static T? DeepCopy(this T source)// where T : new() { if (!typeof(T).IsSerializable) { return default(T);// 직렬화 불가능한 경우 기본값 반환 } try { object result = null; using (var ms = new MemoryStream()) { var formatter = new BinaryFormatter(); formatter.Serialize(ms, source);// 객체를 메모리 스트림에 직렬화 ms.Position = 0;// 스트림 위치 초기화 result = (T)formatter.Deserialize(ms);// 역직렬화하여 새 객체 생성 ms.Close();// 스트림 닫기 } return (T)result; } catch (Exception ex) { return default(T);// 예외 발생 시 기본값 반환 } } /// /// 객체를 바이트 배열로 직렬화합니다. /// /// 직렬화할 객체의 타입 (Serializable 속성이 필요) /// 직렬화할 객체 /// 직렬화된 바이트 배열 또는 실패 시 null /// /// /// [Serializable] /// public class Person /// { /// public string Name { get; set; } /// public int Age { get; set; } /// } /// /// // 사용 예시 /// var person = new Person { Name = "홍길동", Age = 30 }; /// byte[] data = person.SerializeToBytes(); /// // 직렬화된 바이트 배열을 저장하거나 네트워크 전송 가능 /// /// public static byte[] SerializeToBytes(this T obj) where T : class { if (obj == null || !typeof(T).IsSerializable) return null; try { using (var ms = new MemoryStream()) { var formatter = new BinaryFormatter(); formatter.Serialize(ms, obj); return ms.ToArray(); } } catch (Exception) { return null; } } /// /// 바이트 배열에서 객체로 역직렬화합니다. /// /// 역직렬화할 객체 타입 (Serializable 속성이 필요) /// 역직렬화할 바이트 배열 /// 역직렬화된 객체 또는 실패 시 null /// /// /// // 바이트 배열에서 객체 복원 /// byte[] savedData = GetSavedDataFromSomewhere(); /// Person restoredPerson = savedData.DeserializeFromBytes(); /// /// if (restoredPerson != null) /// { /// Console.WriteLine($"이름: {restoredPerson.Name}, 나이: {restoredPerson.Age}"); /// } /// /// public static T DeserializeFromBytes(this byte[] bytes) where T : class { if (bytes == null || bytes.Length == 0 || !typeof(T).IsSerializable) return null; try { using (var ms = new MemoryStream(bytes)) { var formatter = new BinaryFormatter(); return (T)formatter.Deserialize(ms); } } catch (Exception) { return null; } } /// /// 객체를 파일에 직렬화하여 저장합니다. /// /// 직렬화할 객체의 타입 (Serializable 속성이 필요) /// 저장할 객체 /// 저장할 파일 경로 /// 성공 여부 /// /// /// var settings = new GameSettings { Volume = 0.8f, Difficulty = "Hard" }; /// bool success = settings.SerializeToFile("Assets/settings.dat"); /// /// public static bool SerializeToFile(this T obj, string filePath) where T : class { if (obj == null || !typeof(T).IsSerializable || string.IsNullOrEmpty(filePath)) return false; try { using (var fs = new FileStream(filePath, FileMode.Create)) { var formatter = new BinaryFormatter(); formatter.Serialize(fs, obj); return true; } } catch (Exception) { return false; } } /// /// 파일에서 객체를 역직렬화하여 로드합니다. /// /// 역직렬화할 객체 타입 (Serializable 속성이 필요) /// 로드할 파일 경로 /// 역직렬화된 객체 또는 실패 시 null /// /// /// GameSettings settings = DeserializeFromFile("Assets/settings.dat"); /// if (settings != null) /// { /// ApplySettings(settings.Volume, settings.Difficulty); /// } /// /// public static T DeserializeFromFile(string filePath) where T : class { if (string.IsNullOrEmpty(filePath) || !File.Exists(filePath) || !typeof(T).IsSerializable) return null; try { using (var fs = new FileStream(filePath, FileMode.Open)) { var formatter = new BinaryFormatter(); return (T)formatter.Deserialize(fs); } } catch (Exception) { return null; } } } }