309 lines
9.9 KiB
C#
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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
} |