0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【C#】jsonをライブラリを使わずシリアライズ/デシリアライズする

0
Last updated at Posted at 2025-09-28

プロジェクトの都合上、古いバージョンで新しいライブラリなど入れることができないが、jsonファイルで通信のやりとりを行う必要があるため独自にコーディングする機会があったので備忘録として記載する。

ソースコード

配列やDateTime、クラスにも対応したものが以下のコードになります。

using System.Text;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Collections;

namespace clientForm
{
    internal class JsonSerializer
    {
        public static T Parse<T>(string json) where T : new()
        {
            var result = ParseObject(typeof(T), json);
            return (T)result;
        }

        private static object ParseObject(Type type, string json)
        {
            object obj = Activator.CreateInstance(type);
            var properties = type.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public);
            foreach (var prop in properties)
            {
                if (!prop.CanWrite) continue;
                string pattern = $"\"{prop.Name}\"\\s*:\\s*(\".*?\"|\\d+|\\[.*?\\]|{{.*?}})";
                Match match = Regex.Match(json, pattern);
                if (!match.Success) continue;
                string rawValue = TrimParseValue(match.Groups[1].Value);
                object value = ParsePropertyValue(prop.PropertyType, rawValue);
                prop.SetValue(obj, value);
            }
            return obj;
        }

        /// <summary>
        /// 対応する型にキャスト
        /// </summary>
        public static object ParsePropertyValue(Type type, string rawValue)
        {
            object value = null;

            if (type == typeof(string))
                value = TrimParseValue(rawValue);
            else if (type == typeof(int) || type == typeof(int?))
                value = ParseInt(rawValue);
            else if (type == typeof(float) || type == typeof(float?))
                value = ParseFloat(rawValue);
            else if (type == typeof(bool) || type == typeof(bool?))
                value = rawValue.ToLower().Contains("true");
            else if (type == typeof(DateTime) || type == typeof(DateTime?))
                value = ParseDateTime(rawValue);
            else if (type.IsArray)
            {
                var elementType = type.GetElementType();
                value = ParseArray(elementType, rawValue);
            }
            else if (type.IsClass)
                value = ParseObject(type, rawValue);
            return value;
        }

        /// <summary>
        /// 前後の空白と"を削除
        /// </summary>
        private static string TrimParseValue(string value)
        {
            return value.Trim().Trim('"');
        }

        private static object ParseArray(Type elementType, string raw)
        {
            var itemPattern = "\"(.*?)\"|\\d+|true|false|\\{.*?\\}";
            var matched = Regex.Matches(raw, itemPattern);
            var list = new List<object>();
            foreach (Match match in matched)
            {
                string item = match.Value.Trim();
                object value = ParsePropertyValue(elementType, item);
                list.Add(value);
            }
            var array = Array.CreateInstance(elementType, list.Count);
            for (int i = 0; i < list.Count; i++)
            {
                array.SetValue(list[i], i);
            }
            return array;
        }

        private static int? ParseInt(string value)
        {
            if (string.IsNullOrEmpty(value)) return null;
            if (int.TryParse(value, out int result)) return result;
            return null;
        }

        private static float? ParseFloat(string value)
        {
            if (string.IsNullOrEmpty(value)) return null;
            if (float.TryParse(value, out float result)) return result;
            return null;
        }

        private static DateTime? ParseDateTime(string value)
        {
            if (string.IsNullOrEmpty(value)) return null;
            if (DateTime.TryParse(value, out DateTime result)) return result;
            return null;
        }

        public static string ToJson(object obj)
        {
            if (obj == null) return "null";
            Type type = obj.GetType();
            var properties = type.GetProperties();
            StringBuilder json = new StringBuilder();
            json.Append("{");

            for (int i = 0; i < properties.Length; i++)
            {                 
                var prop = properties[i];
                var value = prop.GetValue(obj, null);
                string formattedValue = FormatValue(value);
                json.Append($"\"{prop.Name}\":{formattedValue}");

                if (i < properties.Length - 1)
                {
                    json.Append(",");
                }
            }
            json.Append("}");
            return json.ToString();
        }

        private static string FormatValue(object value)
        {
            if (value == null) return "null";
            if (value is string || value is char)
            {
                return $"\"{value}\"";
            }
            else if (value is bool)
            {
                return value.ToString().ToLower();
            }
            else if (value is int || value is float)
            {
                return value.ToString();
            }
            else if (value is DateTime)
            {
                DateTime dt = (DateTime)value;
                return $"\"{dt:yyyy-MM-ddTHH:mm:ss}\"";
            }
            else if (value is IEnumerable)
            {
                var enumerable = (IEnumerable)value;
                StringBuilder arrayJson = new StringBuilder();
                arrayJson.Append("[");
                bool first = true;
                foreach (var item in enumerable)
                {
                    if (!first)
                    {
                        arrayJson.Append(",");
                    }
                    arrayJson.Append(FormatValue(item));
                    first = false;
                }
                arrayJson.Append("]");
                return arrayJson.ToString();
            }
            // ネストされたクラス対応(再帰)
            return ToJson(value);
        }
    }
}

株式会社ONE WEDGE

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?