using System; using System.Collections.Generic; using System.Text; namespace UVC.Extention { /// /// Dictionary 클래스에 대한 확장 메소드를 제공하는 클래스입니다. /// public static class DictionaryEx { /// /// Dictionary를 JSON 문자열로 변환합니다. /// 중첩된 Dictionary 객체도 재귀적으로 처리합니다. /// /// Dictionary의 키 타입 /// Dictionary의 값 타입 /// JSON 문자열로 변환할 Dictionary 객체 /// JSON 형식의 문자열 /// /// /// var dict = new Dictionary /// { /// { "name", "홍길동" }, /// { "age", 30 }, /// { "address", new Dictionary { { "city", "서울" }, { "zip", "12345" } } } /// }; /// /// string json = dict.ToJson(); /// // 결과: {"name":"홍길동","age":"30","address":{"city":"서울","zip":"12345"}} /// /// public static string ToJson(this IDictionary dict) { if (dict == null || dict.Count == 0) return "{}"; var sb = new StringBuilder("{"); foreach (var kvp in dict) { sb.Append($"\"{kvp.Key}\":"); // 값이 null인 경우 처리 if (kvp.Value == null) { sb.Append("null,"); continue; } // 값이 중첩된 Dictionary인 경우 재귀적으로 처리 if (kvp.Value is IDictionary dictObject) { string nestedJson = ToJson(dictObject); sb.Append($"{nestedJson},"); } else if (kvp.Value is IDictionary dictStringObject) { string nestedJson = ToJson(dictStringObject); sb.Append($"{nestedJson},"); } else if (kvp.Value is IDictionary dictStringString) { string nestedJson = ToJson(dictStringString); sb.Append($"{nestedJson},"); } // 값이 숫자인 경우 따옴표 없이 추가 else if (IsNumericType(kvp.Value.GetType())) { sb.Append($"{kvp.Value},"); } // 값이 불리언인 경우 따옴표 없이 추가 (소문자 true/false) else if (kvp.Value is bool boolValue) { sb.Append($"{boolValue.ToString().ToLowerInvariant()},"); } // 그 외의 경우 문자열로 처리 else { // 특수 문자를 이스케이프 처리 string escapedValue = EscapeJsonString(kvp.Value.ToString()); sb.Append($"\"{escapedValue}\","); } } if (dict.Count > 0) { sb.Length--; // 마지막 쉼표(,) 제거 } sb.Append("}"); return sb.ToString(); } /// /// 주어진 타입이 숫자형인지 확인합니다. /// /// 검사할 타입 /// 숫자형이면 true, 아니면 false private static bool IsNumericType(Type type) { if (type == null) return false; switch (Type.GetTypeCode(type)) { case TypeCode.Byte: case TypeCode.SByte: case TypeCode.Int16: case TypeCode.Int32: case TypeCode.Int64: case TypeCode.UInt16: case TypeCode.UInt32: case TypeCode.UInt64: case TypeCode.Single: case TypeCode.Double: case TypeCode.Decimal: return true; default: return false; } } /// /// JSON 문자열에서 특수 문자를 이스케이프 처리합니다. /// /// 이스케이프 처리할 문자열 /// 이스케이프 처리된 문자열 private static string EscapeJsonString(string value) { if (string.IsNullOrEmpty(value)) return value; StringBuilder sb = new StringBuilder(); foreach (char c in value) { switch (c) { case '\\': sb.Append("\\\\"); break; case '\"': sb.Append("\\\""); break; case '\n': sb.Append("\\n"); break; case '\r': sb.Append("\\r"); break; case '\t': sb.Append("\\t"); break; case '\b': sb.Append("\\b"); break; case '\f': sb.Append("\\f"); break; default: if (c < 32) // 제어 문자 { sb.Append($"\\u{(int)c:X4}"); } else { sb.Append(c); } break; } } return sb.ToString(); } } }