Files
XRLib/Assets/Scripts/UVC/Data/DataObject.cs
2025-06-05 20:09:28 +09:00

309 lines
9.9 KiB
C#

using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
namespace UVC.Data
{
public class DataObject : Dictionary<string, object>, IDataObject
{
// 직접적인 변경이 있었던 키를 저장하는 리스트
protected List<string> changedProperies = new List<string>();
public ReadOnlyCollection<string> ChangedProperies => changedProperies.AsReadOnly();
// 기존에 있던 속성 키를 추적하기 위한 집합
private HashSet<string> existingProperties = new HashSet<string>();
public DataObject()
{
}
public DataObject(JObject other)
{
// JObject로부터 속성을 복사
foreach (var prop in other.Properties())
{
// JToken을 object로 변환
this[prop.Name] = ConvertJTokenToObject(prop.Value);
existingProperties.Add(prop.Name);
}
}
// Dictionary로 초기화하는 생성자 추가
public DataObject(Dictionary<string, object> dictionary) : base(dictionary)
{
// 생성자에서 초기 속성들을 기존 속성으로 등록
foreach (var key in dictionary.Keys)
{
existingProperties.Add(key);
}
}
// JToken을 실제 객체로 변환하는 헬퍼 메서드
private object ConvertJTokenToObject(JToken token)
{
switch (token.Type)
{
case JTokenType.String:
return token.ToString();
case JTokenType.Integer:
return token.ToObject<int>();
case JTokenType.Float:
return token.ToObject<float>();
case JTokenType.Boolean:
return token.ToObject<bool>();
case JTokenType.Object:
return new DataObject((JObject)token);
case JTokenType.Array:
JArray array = (JArray)token;
return new DataArray(array);
default:
return token.ToString();
}
}
/// <summary>
/// 모든 프로퍼티를 변경된 것으로 표시합니다.
/// </summary>
public void ChangeAll()
{
changedProperies.Clear();
foreach (var key in this.Keys)
{
changedProperies.Add(key);
}
}
/// <summary>
/// 변경된 키 목록을 초기화합니다.
/// </summary>
public void ClearChangedKeys()
{
changedProperies.Clear();
}
/// <summary>
/// 속성이 변경될 때 호출되는 메서드입니다.
/// </summary>
protected virtual void OnPropertyChanged(string propertyName)
{
// 기존에 존재하던 속성인 경우에만 변경된 것으로 추적
if (existingProperties.Contains(propertyName))
{
if (!changedProperies.Contains(propertyName))
{
changedProperies.Add(propertyName);
}
}
else
{
// 새로 추가된 속성은 기존 속성 목록에 추가
existingProperties.Add(propertyName);
}
}
/// <summary>
/// 새 속성을 추가할 때 이벤트 연결을 처리합니다.
/// </summary>
public new void Add(string propertyName, object value)
{
// 추가하기 전에 확인 - 속성이 이미 있는지 확인
bool isExisting = ContainsKey(propertyName);
// 기본 구현 호출
base.Add(propertyName, value);
// 새로 추가된 속성이면 기존 속성 목록에 추가
if (!isExisting)
{
existingProperties.Add(propertyName);
}
}
/// <summary>
/// 인덱서를 통한 속성 설정을 처리합니다.
/// </summary>
public new object this[string key]
{
get => base[key];
set
{
// 속성 설정 전에 기존에 있는 속성인지 확인
bool isExisting = ContainsKey(key) || existingProperties.Contains(key);
// 기본 구현 호출
base[key] = value;
// 기존 속성이었다면 변경된 것으로 처리
if (isExisting)
{
if (!changedProperies.Contains(key))
{
changedProperies.Add(key);
}
}
else
{
// 새로 추가된 속성은 기존 속성으로 등록
existingProperties.Add(key);
}
OnPropertyChanged(key);
}
}
public int GetInt(string propertyName, int defaultValue = 0)
{
if (TryGetValue(propertyName, out object value) && value != null)
{
if (value is int intValue)
return intValue;
return Convert.ToInt32(value);
}
return defaultValue;
}
public string GetString(string propertyName, string defaultValue = "")
{
if (TryGetValue(propertyName, out object value) && value != null)
{
return value.ToString();
}
return defaultValue;
}
public bool GetBool(string propertyName, bool defaultValue = false)
{
if (TryGetValue(propertyName, out object value) && value != null)
{
if (value is bool boolValue)
return boolValue;
return Convert.ToBoolean(value);
}
return defaultValue;
}
public float GetFloat(string propertyName, float defaultValue = 0f)
{
if (TryGetValue(propertyName, out object value) && value != null)
{
if (value is float floatValue)
return floatValue;
return Convert.ToSingle(value);
}
return defaultValue;
}
public double GetDouble(string propertyName, double defaultValue = 0.0)
{
if (TryGetValue(propertyName, out object value) && value != null)
{
if (value is double doubleValue)
return doubleValue;
return Convert.ToDouble(value);
}
return defaultValue;
}
public DateTime? GetDateTime(string propertyName, DateTime? defaultValue = null)
{
if (TryGetValue(propertyName, out object value) && value != null)
{
if (value is DateTime dateTime)
return dateTime;
return Convert.ToDateTime(value);
}
return defaultValue;
}
public T GetEnum<T>(string propertyName, T defaultValue = default) where T : Enum
{
if (TryGetValue(propertyName, out object value) && value != null)
{
if (value is T enumValue)
return enumValue;
return (T)Enum.Parse(typeof(T), value.ToString());
}
return defaultValue;
}
public DataArray GetDataArray(string propertyName, DataArray? defaultValue = null)
{
if (TryGetValue(propertyName, out object value) && value != null)
{
if (value is DataArray dataArray)
return dataArray;
if (value is JArray jArray)
return new DataArray(jArray);
}
return defaultValue;
}
public DataObject GetDataObject(string propertyName, DataObject? defaultValue = null)
{
if (TryGetValue(propertyName, out object value) && value != null)
{
if (value is DataObject dataObject)
return dataObject;
if (value is JObject jObject)
return new DataObject(jObject);
if (value is Dictionary<string, object> dict)
return new DataObject(dict);
}
return defaultValue;
}
/// <summary>
/// 속성이 제거될 때 기존 속성 목록에서도 제거합니다.
/// </summary>
public new bool Remove(string key)
{
bool result = base.Remove(key);
if (result)
{
existingProperties.Remove(key);
changedProperies.Remove(key);
}
return result;
}
/// <summary>
/// 모든 속성을 제거할 때 기존 속성 목록과 변경된 키 목록도 초기화합니다.
/// </summary>
public void RemoveAll()
{
base.Clear();
existingProperties.Clear();
changedProperies.Clear();
}
/// <summary>
/// JObject로 변환
/// </summary>
public JObject ToJObject()
{
JObject result = new JObject();
foreach (var kvp in this)
{
result[kvp.Key] = JToken.FromObject(kvp.Value);
}
return result;
}
public void SetDifferent(DataObject other)
{
changedProperies.Clear();
foreach (var keyValue in other)
{
if(!this.ContainsKey(keyValue.Key) || !this[keyValue.Key].Equals(keyValue.Value))
{
this[keyValue.Key] = keyValue.Value;
changedProperies.Add(keyValue.Key);
}
}
}
}
}