Files
XRLib/Assets/Scripts/UVC/Data/DataArray.cs

377 lines
11 KiB
C#
Raw Normal View History

2025-06-05 20:09:28 +09:00
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
namespace UVC.Data
{
/// <summary>
/// DataObject 객체 컬렉션의 변경사항을 추적하는 데이터 배열 클래스
/// </summary>
public class DataArray : List<DataObject>, IDataObject
{
// 추가 된 항목 목록
protected List<DataObject> addedList = new List<DataObject>();
// 제거 된 항목 목록
protected List<DataObject> removedList = new List<DataObject>();
// 수정 된 항목 목록
protected List<DataObject> modifiedList = new List<DataObject>();
// 추가된 항목에 접근할 수 있는 읽기 전용 컬렉션
public ReadOnlyCollection<DataObject> AddedItems => addedList.AsReadOnly();
// 제거된 항목에 접근할 수 있는 읽기 전용 컬렉션
public ReadOnlyCollection<DataObject> RemovedItems => removedList.AsReadOnly();
// 제거된 항목에 접근할 수 있는 읽기 전용 컬렉션
public ReadOnlyCollection<DataObject> ModifiedList => modifiedList.AsReadOnly();
/// <summary>
/// 변경 추적 활성화 여부
/// </summary>
public bool IsChangeTracking { get; set; } = false;
/// <summary>
/// 기본 생성자
/// </summary>
public DataArray() : base()
{
}
/// <summary>
/// 초기 용량을 지정하는 생성자
/// </summary>
/// <param name="capacity">초기 용량</param>
public DataArray(int capacity) : base(capacity)
{
}
/// <summary>
/// 기존 컬렉션으로부터 생성하는 생성자
/// </summary>
/// <param name="collection">초기 항목을 포함하는 컬렉션</param>
public DataArray(IEnumerable<DataObject> collection) : base(collection)
{
}
public DataArray(string jsonString) : base()
{
if (!string.IsNullOrEmpty(jsonString))
{
try
{
JArray jArray = JArray.Parse(jsonString);
foreach (var item in jArray)
{
Add(ConvertToDataObject(item));
}
}
catch (Exception ex)
{
throw new ArgumentException("Invalid JSON string format.", nameof(jsonString), ex);
}
}
}
/// <summary>
/// JArray로부터 DataArray를 생성하는 생성자
/// </summary>
/// <param name="jArray">JSON 배열</param>
public DataArray(JArray jArray) : base()
{
if (jArray != null)
{
foreach (var item in jArray)
{
Add(ConvertToDataObject(item));
}
}
}
/// <summary>
/// JToken을 DataObject로 변환합니다.
/// </summary>
private DataObject ConvertToDataObject(JToken token)
{
if (token.Type == JTokenType.Object)
{
return new DataObject((JObject)token);
}
else
{
// JObject가 아닌 경우, 새 DataObject를 만들고 값을 넣어줍니다
var dataObject = new DataObject();
dataObject.Add("value", ConvertJTokenToObject(token));
return dataObject;
}
}
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 InitData()
{
addedList.Clear();
addedList.AddRange(this);
}
/// <summary>
/// 다른 DataObject와 현재 객체를 비교하여 다른 부분만 설정합니다.
/// 변경된 키는 자동으로 추적됩니다.
/// </summary>
/// <param name="other">비교할 DataObject</param>
public void UpdateDifferent(IDataObject other)
{
if (other == null) return;
if (other is DataArray otherArray)
{
addedList.Clear();
removedList.Clear();
modifiedList.Clear();
// 현재 DataArray와 비교하여 변경된 항목을 추적
for (int i = 0; i < Math.Max(this.Count, otherArray.Count); i++)
{
if (i < this.Count && i < otherArray.Count)
{
if (!this[i].ToString().Equals(otherArray[i].ToString()))
{
modifiedList.Add(this[i]);
this[i].UpdateDifferent(otherArray[i]);
}
}
else if (i < this.Count)
{
removedList.Add(this[i]);
}
else if (i < otherArray.Count)
{
addedList.Add(otherArray[i]);
}
}
}
}
/// <summary>
/// 업데이트 된 객체를 반환합니다.
/// </summary>
/// <returns></returns>
public IDataObject GetUpdatedObject()
{
return this;
}
2025-06-05 20:09:28 +09:00
/// <summary>
/// 항목을 추가합니다.
/// </summary>
/// <param name="item">추가할 항목</param>
public new void Add(DataObject item)
{
base.Add(item);
// 변경 사항을 추적하고 이벤트 발생
if (IsChangeTracking)
{
int index = Count - 1;
addedList.Add(item);
}
}
/// <summary>
/// 항목을 제거합니다.
/// </summary>
/// <param name="item">제거할 항목</param>
/// <returns>제거 성공 여부</returns>
public new bool Remove(DataObject item)
{
int index = IndexOf(item);
if (index >= 0)
{
RemoveAt(index);
return true;
}
return false;
}
/// <summary>
/// 지정된 인덱스의 항목을 제거합니다.
/// </summary>
/// <param name="index">제거할 항목의 인덱스</param>
public new void RemoveAt(int index)
{
if (index < 0 || index >= Count)
throw new ArgumentOutOfRangeException(nameof(index));
DataObject removedItem = this[index];
base.RemoveAt(index);
if (IsChangeTracking)
{
removedList.Add(removedItem);
}
}
/// <summary>
/// 컬렉션의 모든 항목을 제거합니다.
/// </summary>
public new void Clear()
{
if (Count > 0)
{
var oldItems = new List<DataObject>(this);
base.Clear();
if (IsChangeTracking)
{
// 모든 항목을 제거 목록에 추가
removedList.AddRange(oldItems);
}
}
}
/// <summary>
/// 지정된 인덱스에 항목을 삽입합니다.
/// </summary>
/// <param name="index">삽입할 위치</param>
/// <param name="item">삽입할 항목</param>
public new void Insert(int index, DataObject item)
{
base.Insert(index, item);
if (IsChangeTracking)
{
addedList.Add(item);
}
}
/// <summary>
/// 지정된 인덱스의 항목을 교체합니다.
/// </summary>
/// <param name="index">교체할 위치</param>
/// <param name="item">새 항목</param>
public new DataObject this[int index]
{
get { return base[index]; }
set
{
if (index < 0 || index >= Count)
throw new ArgumentOutOfRangeException(nameof(index));
DataObject oldItem = base[index];
base[index] = value;
if (IsChangeTracking)
{
addedList.Add(value);
removedList.Add(oldItem);
}
}
}
/// <summary>
/// 범위의 항목을 추가합니다.
/// </summary>
/// <param name="collection">추가할 항목의 컬렉션</param>
public new void AddRange(IEnumerable<DataObject> collection)
{
if (collection == null)
throw new ArgumentNullException(nameof(collection));
int startIndex = Count;
base.AddRange(collection);
if (IsChangeTracking)
{
var items = collection.ToList();
for (int i = 0; i < items.Count; i++)
{
addedList.Add(items[i]);
}
}
}
/// <summary>
/// 변경된 인덱스 목록을 초기화합니다.
/// </summary>
public void ResetChangedIndices()
{
addedList.Clear();
removedList.Clear();
modifiedList.Clear();
}
/// <summary>
/// 변경 내역을 저장하지 않고 항목을 추가합니다.
/// </summary>
/// <param name="item">추가할 항목</param>
public void AddWithoutTracking(DataObject item)
{
bool oldTracking = IsChangeTracking;
IsChangeTracking = false;
Add(item);
IsChangeTracking = oldTracking;
}
/// <summary>
/// DataArray를 JArray로 변환합니다.
/// </summary>
public JArray ToJArray()
{
JArray array = new JArray();
foreach (var item in this)
{
array.Add(item);
}
return array;
}
/// <summary>
/// DataArray를 JArray로 암시적 변환합니다.
/// </summary>
public static implicit operator JArray(DataArray dataArray)
{
return dataArray.ToJArray();
}
/// <summary>
/// JArray를 DataArray로 암시적 변환합니다.
/// </summary>
public static implicit operator DataArray(JArray jArray)
{
return new DataArray(jArray);
}
}
}