From bb3cc3c37c1a337fd1f3691b17205541834c67cf Mon Sep 17 00:00:00 2001 From: Loretta Date: Fri, 7 Nov 2025 14:10:30 +0100 Subject: [PATCH] CollectionExtensions UpdateCollectionById --- AyCode.Core.targets | 7 +- .../Extensions/CollectionExtensions.cs | 12 + .../SignalRs/AcSignalRDataSource.cs | 340 ++++++++++++------ 3 files changed, 243 insertions(+), 116 deletions(-) diff --git a/AyCode.Core.targets b/AyCode.Core.targets index fd35ae6..ef6f2a0 100644 --- a/AyCode.Core.targets +++ b/AyCode.Core.targets @@ -1,12 +1,17 @@ + AyCode.Core.targets + <_ProjectName>FruitBank + + net9.0 enable enable Debug;Release;Product - bin\FruitBank + bin\$(_ProjectName) \ No newline at end of file diff --git a/AyCode.Core/Extensions/CollectionExtensions.cs b/AyCode.Core/Extensions/CollectionExtensions.cs index 4dbdf47..ce87f21 100644 --- a/AyCode.Core/Extensions/CollectionExtensions.cs +++ b/AyCode.Core/Extensions/CollectionExtensions.cs @@ -27,6 +27,18 @@ namespace AyCode.Core.Extensions return source.UpdateCollectionByIndex(index, dataItem, isRemove); } + public static TrackingState UpdateCollectionById(this IList> source, IId dataItem, bool isRemove) where TId : struct + { + if (source == null) throw new ArgumentNullException(nameof(source), $"source == null"); + + var equalityComparer = EqualityComparer.Default; + if (equalityComparer.Equals(dataItem.Id, default(TId))) throw new ArgumentNullException(nameof(dataItem), "UpdateCollection->dataItem.Id.IsNullOrEmpty()"); + + var index = source.FindIndex(x => equalityComparer.Equals(x.Id, dataItem.Id)); + + return source.UpdateCollectionByIndex(index, dataItem, isRemove); + } + public static TrackingState UpdateCollectionByIndex(this IList source, int index, TDataItem dataItem, bool isRemove) { if (isRemove) diff --git a/AyCode.Services.Server/SignalRs/AcSignalRDataSource.cs b/AyCode.Services.Server/SignalRs/AcSignalRDataSource.cs index 9d1b870..03235a8 100644 --- a/AyCode.Services.Server/SignalRs/AcSignalRDataSource.cs +++ b/AyCode.Services.Server/SignalRs/AcSignalRDataSource.cs @@ -1,43 +1,87 @@ -using System.Collections; -using System.Collections.ObjectModel; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using AyCode.Core.Enums; +using AyCode.Core.Enums; using AyCode.Core.Extensions; using AyCode.Core.Helpers; using AyCode.Core.Interfaces; using AyCode.Services.SignalRs; +using System.Collections; +using System.Collections.ObjectModel; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; namespace AyCode.Services.Server.SignalRs { - public class TrackingItem(TrackingState trackingState, T currentValue, T? originalValue = null) where T : class, IId + //public class TrackingItemGuid(TrackingState trackingState, TDataItem currentValue, TDataItem? originalValue = null) : TrackingItem(trackingState, currentValue, originalValue) + // where TDataItem : class, IId { } + + //public class TrackingItemInt(TrackingState trackingState, TDataItem currentValue, TDataItem? originalValue = null) : TrackingItem(trackingState, currentValue, originalValue) + // where TDataItem : class, IId {} + + public abstract class TrackingItem(TrackingState trackingState, TDataItem currentValue, TDataItem? originalValue = null) where TDataItem : class, IId where TId : struct { public TrackingState TrackingState { get; internal set; } = trackingState; - public T CurrentValue { get; internal set; } = currentValue; - public T? OriginalValue { get; init; } = originalValue; + public TDataItem CurrentValue { get; internal set; } = currentValue; + public TDataItem? OriginalValue { get; init; } = originalValue; - internal TrackingItem UpdateItem(TrackingState trackingState, T newValue) + internal TrackingItem UpdateItem(TrackingState trackingState, TDataItem newValue) //where TTrackingItem : TrackingItem { CurrentValue = newValue; if (TrackingState != TrackingState.Add) TrackingState = trackingState; - return this; + return (TrackingItem)this; } } + //public class ChangeTrackingGuid : ChangeTracking /*: IEnumerable>*/ where TDataItem : class, IId + //{ + // protected override bool HasIdValue(TDataItem dataItem) => !dataItem.Id.IsNullOrEmpty(); - public class ChangeTracking /*: IEnumerable>*/ where T : class, IId + // protected override int FindIndex(TDataItem newValue) => TrackingItems.FindIndex(x => x.CurrentValue.Id == newValue.Id); + + // public override bool TryGetTrackingItem(Guid id, [NotNullWhen(true)] out TrackingItem? trackingItem) + // { + // trackingItem = TrackingItems.FirstOrDefault(x => x.CurrentValue.Id == id); + // return trackingItem != null; + // } + //} + + //public class ChangeTrackingInt : ChangeTracking /*: IEnumerable>*/ where TDataItem : class, IId + //{ + // protected override bool HasIdValue(TDataItem dataItem) => true;//dataItem.Id.IsNullOrEmpty(); + + // protected override int FindIndex(TDataItem newValue) => TrackingItems.FindIndex(x => x.CurrentValue.Id == newValue.Id); + + // public override bool TryGetTrackingItem(int id, [NotNullWhen(true)] out TrackingItem? trackingItem) + // { + // trackingItem = TrackingItems.FirstOrDefault(x => x.CurrentValue.Id == id); + // return trackingItem != null; + // } + //} + + public class ChangeTracking /*: IEnumerable>*/where TDataItem : class, IId where TId : struct { - private readonly List> _trackingItems = []; //TODO: Dictionary... - J. + private readonly EqualityComparer _equalityComparer = EqualityComparer.Default; + private readonly List> _trackingItems = []; //TODO: Dictionary... - J. - internal TrackingItem? AddTrackingItem(TrackingState trackingState, T newValue, T? originalValue = null) + //protected abstract bool HasIdValue(TDataItem dataItem); + //protected abstract int FindIndex(TDataItem newValue); + //public abstract bool TryGetTrackingItem(TId id, [NotNullWhen(true)] out TrackingItem? trackingItem); + + private bool HasIdValue(TDataItem dataItem) => _equalityComparer.Equals(dataItem.Id, default);//dataItem.Id.IsNullOrEmpty(); + public int FindIndex(TDataItem newValue) => _trackingItems.FindIndex(x => _equalityComparer.Equals(x.CurrentValue.Id, newValue.Id)); + public bool TryGetTrackingItem(TId id, [NotNullWhen(true)] out TrackingItem? trackingItem) { - if (newValue.Id.IsNullOrEmpty()) throw new ArgumentNullException(nameof(newValue), $@"currentValue.Id.IsNullOrEmpty()"); + trackingItem = _trackingItems.FirstOrDefault(x => _equalityComparer.Equals(x.CurrentValue.Id, id)); + return trackingItem != null; + } - var itemIndex = _trackingItems.FindIndex(x => x.CurrentValue.Id == newValue.Id); - TrackingItem? trackingItem = null; + internal TrackingItem? AddTrackingItem(TrackingState trackingState, TDataItem newValue, TDataItem? originalValue = null) + { + if (!HasIdValue(newValue)) throw new ArgumentNullException(nameof(newValue), $@"currentValue.Id.IsNullOrEmpty()"); + + var itemIndex = FindIndex(newValue); //_trackingItems.FindIndex(x => x.CurrentValue.Id == newValue.Id); + TrackingItem? trackingItem = null; if (itemIndex > -1) { @@ -50,13 +94,13 @@ namespace AyCode.Services.Server.SignalRs } return trackingItem.UpdateItem(trackingState, newValue); - } if (originalValue != null && Equals(newValue, originalValue)) originalValue = TrackingItemHelpers.JsonClone(originalValue); - trackingItem = new TrackingItem(trackingState, newValue, originalValue); + //trackingItem = new TrackingItem(trackingState, newValue, originalValue); + trackingItem = (TrackingItem)Activator.CreateInstance(typeof(TrackingItem), trackingState, newValue, originalValue)!; _trackingItems.Add(trackingItem); return trackingItem; @@ -64,15 +108,9 @@ namespace AyCode.Services.Server.SignalRs public int Count => _trackingItems.Count; internal void Clear() => _trackingItems.Clear(); - public List> ToList() => _trackingItems.ToList(); + public List> ToList() => _trackingItems.ToList(); - public bool TryGetTrackingItem(Guid id, [NotNullWhen(true)] out TrackingItem? trackingItem) - { - trackingItem = _trackingItems.FirstOrDefault(x => x.CurrentValue.Id == id); - return trackingItem != null; - } - - internal void Remove(TrackingItem trackingItem) => _trackingItems.Remove(trackingItem); + internal void Remove(TrackingItem trackingItem) => _trackingItems.Remove(trackingItem); //public IEnumerator> GetEnumerator() //{ @@ -85,16 +123,52 @@ namespace AyCode.Services.Server.SignalRs //} } + //[Serializable] + //[DebuggerDisplay("Count = {Count}")] + //public abstract class AcSignalRDataSourceGuid : AcSignalRDataSource + // where TDataItem : class, IId where TIList : class, IList + //{ + // public AcSignalRDataSourceGuid(AcSignalRClientBase signalRClient, SignalRCrudTags signalRCrudTags, object[]? contextIds = null) + // : base(signalRClient, signalRCrudTags, contextIds) + // { + // } + + // protected override bool HasIdValue(TDataItem dataItem) => !dataItem.Id.IsNullOrEmpty(); + // protected override bool IdEquals(Guid id1, Guid id2) => id1 == id2; + + // protected override int FindIndexInnerList(Guid id) => InnerList.FindIndex(x => x.Id == id); + // protected override TDataItem? FirstOrDefaultInnerList(Guid id) => InnerList.FirstOrDefault(x => x.Id == id); + //} + + //[Serializable] + //[DebuggerDisplay("Count = {Count}")] + //public abstract class AcSignalRDataSourceInt : AcSignalRDataSource + // where TDataItem : class, IId where TIList : class, IList + //{ + // public AcSignalRDataSourceInt(AcSignalRClientBase signalRClient, SignalRCrudTags signalRCrudTags, object[]? contextIds = null) + // : base(signalRClient, signalRCrudTags, contextIds) + // { + // } + + // protected override bool HasIdValue(TDataItem dataItem) => true; + // protected override bool IdEquals(int id1, int id2) => id1 == id2; + + // protected override int FindIndexInnerList(int id) => InnerList.FindIndex(x => x.Id == id); + // protected override TDataItem? FirstOrDefaultInnerList(int id) => InnerList.FirstOrDefault(x => x.Id == id); + //} [Serializable] [DebuggerDisplay("Count = {Count}")] - public class AcSignalRDataSource : IList, IList, IReadOnlyList where T : class, IId + public abstract class AcSignalRDataSource : IList, IList, IReadOnlyList + where TDataItem : class, IId where TId : struct + where TIList : class, IList { private readonly object _syncRoot = new(); + private readonly EqualityComparer _equalityComparer = EqualityComparer.Default; - protected List InnerList = []; //TODO: Dictionary??? - J. - protected readonly ChangeTracking TrackingItems = new(); + protected TIList InnerList = Activator.CreateInstance();// []; //TODO: Dictionary??? - J. + protected readonly ChangeTracking TrackingItems = Activator.CreateInstance>(); public object[]? ContextIds; public string? FilterText { get; set; } @@ -102,9 +176,19 @@ namespace AyCode.Services.Server.SignalRs public AcSignalRClientBase SignalRClient; protected readonly SignalRCrudTags SignalRCrudTags; - public Func, Task>? OnDataSourceItemChanged; + public Func, Task>? OnDataSourceItemChanged; public Func? OnDataSourceLoaded; + //protected abstract bool HasIdValue(TDataItem dataItem); + //protected abstract bool IdEquals(TId id1, TId id2); + //protected abstract int FindIndexInnerList(TId id); + //protected abstract TDataItem? FirstOrDefaultInnerList(TId id); + + protected bool HasIdValue(TDataItem dataItem) => _equalityComparer.Equals(dataItem.Id, default);//dataItem.Id.IsNullOrEmpty(); + protected bool IdEquals(TId id1, TId id2) => _equalityComparer.Equals(id1, id2); + protected int FindIndexInnerList(TId id) => InnerList.FindIndex(x => IdEquals(x.Id, id)); + protected TDataItem? FirstOrDefaultInnerList(TId id) => InnerList.FirstOrDefault(x => IdEquals(x.Id, id)); + public AcSignalRDataSource(AcSignalRClientBase signalRClient, SignalRCrudTags signalRCrudTags, object[]? contextIds = null) { //if (contextIds != null) (ContextIds = new List()).AddRange(contextIds); @@ -120,21 +204,21 @@ namespace AyCode.Services.Server.SignalRs public bool HasWorkingReferenceList { get; private set; } - public void SetWorkingReferenceList(List workingList) + public void SetWorkingReferenceList(TIList workingIList) { - if (workingList == null!) return; //throw new ArgumentNullException(nameof(workingList)); + if (workingIList == null!) return; //throw new ArgumentNullException(nameof(workingList)); Monitor.Enter(_syncRoot); try { HasWorkingReferenceList = true; - if (ReferenceEquals(InnerList, workingList)) return; + if (ReferenceEquals(InnerList, workingIList)) return; - if (workingList.Count == 0) workingList.AddRange(InnerList); + if (workingIList.Count == 0) AddRange(InnerList, workingIList); Clear(true); - InnerList = workingList; + InnerList = workingIList; } finally { @@ -161,7 +245,7 @@ namespace AyCode.Services.Server.SignalRs { if (SignalRCrudTags.GetAllMessageTag == AcSignalRTags.None) throw new ArgumentException($"SignalRCrudTags.GetAllMessageTag == SignalRTags.None"); - var responseData = (await SignalRClient.GetAllAsync>(SignalRCrudTags.GetAllMessageTag, GetContextParams())) ?? throw new NullReferenceException(); + var responseData = (await SignalRClient.GetAllAsync(SignalRCrudTags.GetAllMessageTag, GetContextParams())) ?? throw new NullReferenceException(); await LoadDataSource(responseData, false, false, clearChangeTracking); } @@ -170,7 +254,7 @@ namespace AyCode.Services.Server.SignalRs { if (SignalRCrudTags.GetAllMessageTag == AcSignalRTags.None) throw new ArgumentException($"SignalRCrudTags.GetAllMessageTag == SignalRTags.None"); - return SignalRClient.GetAllAsync>(SignalRCrudTags.GetAllMessageTag, result=> + return SignalRClient.GetAllAsync(SignalRCrudTags.GetAllMessageTag, result=> { if (result.Status != SignalResponseStatus.Success || result.ResponseData == null) throw new NullReferenceException($"LoadDataSourceAsync; result.Status != SignalResponseStatus.Success || result.ResponseData == null; Status: {SignalResponseStatus.Success}"); @@ -179,7 +263,19 @@ namespace AyCode.Services.Server.SignalRs }, GetContextParams()); } - public async Task LoadDataSource(IList fromSource, bool refreshDataFromDbAsync = false, bool setSourceToWorkingReferenceList = false, bool clearChangeTracking = true) + protected void AddRange(IEnumerable source, TIList destination) + { + if (destination is List dest) dest.AddRange(source); + else + { + foreach (var dataItem in source) + destination.Add(dataItem); + } + } + + public void AddRange(IEnumerable source) => AddRange(source, InnerList); + + public async Task LoadDataSource(TIList fromSource, bool refreshDataFromDbAsync = false, bool setSourceToWorkingReferenceList = false, bool clearChangeTracking = true) { Monitor.Enter(_syncRoot); @@ -189,8 +285,8 @@ namespace AyCode.Services.Server.SignalRs { Clear(clearChangeTracking); - if (setSourceToWorkingReferenceList && fromSource is List fromSourceList) SetWorkingReferenceList(fromSourceList); - else InnerList.AddRange(fromSource); + if (setSourceToWorkingReferenceList) SetWorkingReferenceList(fromSource); + else AddRange(fromSource); } else if (clearChangeTracking) TrackingItems.Clear(); @@ -204,23 +300,23 @@ namespace AyCode.Services.Server.SignalRs if (OnDataSourceLoaded != null) await OnDataSourceLoaded.Invoke(); } - public async Task LoadItem(Guid id) + public async Task LoadItem(TId id) { if (SignalRCrudTags.GetItemMessageTag == AcSignalRTags.None) throw new ArgumentException($"SignalRCrudTags.GetItemMessageTag == SignalRTags.None"); - T? resultitem = null; + TDataItem? resultitem = null; Monitor.Enter(_syncRoot); try { - resultitem = await SignalRClient.GetByIdAsync(SignalRCrudTags.GetItemMessageTag, id); + resultitem = await SignalRClient.GetByIdAsync(SignalRCrudTags.GetItemMessageTag, id); if (resultitem == null) return null; if (TryGetIndex(id, out var index)) InnerList[index] = resultitem; else InnerList.Add(resultitem); - var eventArgs = new ItemChangedEventArgs(resultitem, TrackingState.Get); + var eventArgs = new ItemChangedEventArgs(resultitem, TrackingState.Get); if (OnDataSourceItemChanged != null) await OnDataSourceItemChanged.Invoke(eventArgs); } finally @@ -237,7 +333,7 @@ namespace AyCode.Services.Server.SignalRs /// /// /// - public T this[int index] + public TDataItem this[int index] { get { @@ -268,16 +364,16 @@ namespace AyCode.Services.Server.SignalRs } } - public void Add(T newValue) + public void Add(TDataItem newValue) { - if (newValue.Id.IsNullOrEmpty()) throw new ArgumentNullException(nameof(newValue), @"Add->newValue.Id.IsNullOrEmpty()"); + if (!HasIdValue(newValue)) throw new ArgumentNullException(nameof(newValue), @"Add->newValue.Id.IsNullOrEmpty()"); Monitor.Enter(_syncRoot); try { if (Contains(newValue)) - throw new ArgumentException($@"It already contains this Id! Id: {newValue.Id}", nameof(newValue)); + throw new ArgumentException($@"It already contains this Id! {newValue}", nameof(newValue)); UnsafeAdd(newValue); } @@ -293,7 +389,7 @@ namespace AyCode.Services.Server.SignalRs /// /// /// - public async Task Add(T newValue, bool autoSave) + public async Task Add(TDataItem newValue, bool autoSave) { Monitor.Enter(_syncRoot); @@ -315,9 +411,9 @@ namespace AyCode.Services.Server.SignalRs /// /// /// - public async Task AddOrUpdate(T newValue, bool autoSave) + public async Task AddOrUpdate(TDataItem newValue, bool autoSave) { - if (newValue.Id.IsNullOrEmpty()) throw new ArgumentNullException(nameof(newValue), @"AddOrUpdate->newValue.Id.IsNullOrEmpty()"); + if (!HasIdValue(newValue)) throw new ArgumentNullException(nameof(newValue), @"AddOrUpdate->newValue.Id.IsNullOrEmpty()"); Monitor.Enter(_syncRoot); @@ -342,7 +438,7 @@ namespace AyCode.Services.Server.SignalRs // } //} - protected void UnsafeAdd(T newValue) + protected void UnsafeAdd(TDataItem newValue) { TrackingItems.AddTrackingItem(TrackingState.Add, newValue); InnerList.Add(newValue); @@ -356,16 +452,16 @@ namespace AyCode.Services.Server.SignalRs /// /// /// - public void Insert(int index, T newValue) + public void Insert(int index, TDataItem newValue) { - if (newValue.Id.IsNullOrEmpty()) throw new ArgumentNullException(nameof(newValue), @"Insert->newValue.Id.IsNullOrEmpty()"); + if (!HasIdValue(newValue)) throw new ArgumentNullException(nameof(newValue), @"Insert->newValue.Id.IsNullOrEmpty()"); Monitor.Enter(_syncRoot); try { if (Contains(newValue)) - throw new ArgumentException($@"Insert; It already contains this Id! Id: {newValue.Id}", nameof(newValue)); + throw new ArgumentException($@"Insert; It already contains this Id! {newValue}", nameof(newValue)); TrackingItems.AddTrackingItem(TrackingState.Add, newValue); InnerList.Insert(index, newValue); @@ -376,7 +472,7 @@ namespace AyCode.Services.Server.SignalRs } } - public async Task Insert(int index, T newValue, bool autoSave) + public async Task Insert(int index, TDataItem newValue, bool autoSave) { Monitor.Enter(_syncRoot); @@ -396,7 +492,7 @@ namespace AyCode.Services.Server.SignalRs /// /// /// - public Task Update(T newItem, bool autoSave) => Update(IndexOf(newItem), newItem, autoSave); + public Task Update(TDataItem newItem, bool autoSave) => Update(IndexOf(newItem), newItem, autoSave); /// /// UpdateMessageTag @@ -408,7 +504,7 @@ namespace AyCode.Services.Server.SignalRs /// /// /// /// - public async Task Update(int index, T newValue, bool autoSave) + public async Task Update(int index, TDataItem newValue, bool autoSave) { Monitor.Enter(_syncRoot); @@ -424,10 +520,10 @@ namespace AyCode.Services.Server.SignalRs } } - private void UpdateUnsafe(int index, T newValue) + private void UpdateUnsafe(int index, TDataItem newValue) { - if (default(T) != null && newValue == null) throw new NullReferenceException(nameof(newValue)); - if (newValue.Id.IsNullOrEmpty()) throw new ArgumentNullException(nameof(newValue), @"UpdateUnsafe->newValue.Id.IsNullOrEmpty()"); + if (default(TDataItem) != null && newValue == null) throw new NullReferenceException(nameof(newValue)); + if (!HasIdValue(newValue)) throw new ArgumentNullException(nameof(newValue), @"UpdateUnsafe->newValue.Id.IsNullOrEmpty()"); if ((uint)index >= (uint)Count) throw new ArgumentOutOfRangeException(nameof(index)); Monitor.Enter(_syncRoot); @@ -436,8 +532,8 @@ namespace AyCode.Services.Server.SignalRs { var currentItem = InnerList[index]; - if (currentItem.Id != newValue.Id) - throw new ArgumentException($@"UpdateUnsafe; currentItem.Id != item.Id! Id: {newValue.Id}", nameof(newValue)); + if (!IdEquals(currentItem.Id, newValue.Id)) + throw new ArgumentException($@"UpdateUnsafe; currentItem.Id != item.Id! {newValue}", nameof(newValue)); TrackingItems.AddTrackingItem(TrackingState.Update, newValue, currentItem); InnerList[index] = newValue; @@ -454,7 +550,7 @@ namespace AyCode.Services.Server.SignalRs /// /// /// - public bool Remove(T item) + public bool Remove(TDataItem item) { Monitor.Enter(_syncRoot); @@ -473,7 +569,22 @@ namespace AyCode.Services.Server.SignalRs } } - public async Task Remove(T item, bool autoSave) + public async Task Remove(TId id, bool autoSave) + { + Monitor.Enter(_syncRoot); + + try + { + var item = FirstOrDefaultInnerList(id); + return item == null || await Remove(item, autoSave); + } + finally + { + Monitor.Exit(_syncRoot); + } + } + + public async Task Remove(TDataItem item, bool autoSave) { Monitor.Enter(_syncRoot); @@ -497,7 +608,7 @@ namespace AyCode.Services.Server.SignalRs /// /// /// - public bool TryRemove(Guid id, out T? item) + public bool TryRemove(TId id, out TDataItem? item) { Monitor.Enter(_syncRoot); @@ -509,7 +620,6 @@ namespace AyCode.Services.Server.SignalRs { Monitor.Exit(_syncRoot); } - } /// @@ -526,7 +636,7 @@ namespace AyCode.Services.Server.SignalRs try { var currentItem = InnerList[index]; - if (currentItem.Id.IsNullOrEmpty()) throw new ArgumentNullException(nameof(currentItem), $@"RemoveAt->item.Id.IsNullOrEmpty(); index: {index}"); + if (!HasIdValue(currentItem)) throw new ArgumentNullException(nameof(currentItem), $@"RemoveAt->item.Id.IsNullOrEmpty(); index: {index}"); TrackingItems.AddTrackingItem(TrackingState.Remove, currentItem, currentItem); InnerList.RemoveAt(index); @@ -560,7 +670,7 @@ namespace AyCode.Services.Server.SignalRs /// /// /// - public List> GetTrackingItems() + public List> GetTrackingItems() { Monitor.Enter(_syncRoot); @@ -574,7 +684,7 @@ namespace AyCode.Services.Server.SignalRs } } - public void SetTrackingStateToUpdate(T item) + public void SetTrackingStateToUpdate(TDataItem item) { Monitor.Enter(_syncRoot); @@ -603,7 +713,7 @@ namespace AyCode.Services.Server.SignalRs /// /// /// - public bool TryGetTrackingItem(Guid id, [NotNullWhen(true)] out TrackingItem? trackingItem) + public bool TryGetTrackingItem(TId id, [NotNullWhen(true)] out TrackingItem? trackingItem) { Monitor.Enter(_syncRoot); @@ -622,7 +732,7 @@ namespace AyCode.Services.Server.SignalRs /// /// /// Unsaved items - public async Task>> SaveChanges() + public async Task>> SaveChanges() { Monitor.Enter(_syncRoot); @@ -677,13 +787,13 @@ namespace AyCode.Services.Server.SignalRs /// /// /// - public async Task SaveItem(Guid id) + public async Task SaveItem(TId id) { Monitor.Enter(_syncRoot); try { - T resultItem = null!; + TDataItem resultItem = null!; if (TryGetTrackingItem(id, out var trackingItem)) resultItem = await SaveTrackingItemUnsafe(trackingItem); @@ -697,13 +807,13 @@ namespace AyCode.Services.Server.SignalRs } } - public async Task SaveItem(Guid id, TrackingState trackingState) + public async Task SaveItem(TId id, TrackingState trackingState) { //Monitor.Enter(_syncRoot); try { - T resultItem = null!; + TDataItem resultItem = null!; if (TryGetValue(id, out var item)) resultItem = await SaveItem(item, trackingState); @@ -717,15 +827,15 @@ namespace AyCode.Services.Server.SignalRs } } - public Task SaveItem(T item, TrackingState trackingState) => SaveItemUnsafe(item, trackingState); + public Task SaveItem(TDataItem item, TrackingState trackingState) => SaveItemUnsafe(item, trackingState); - protected Task SaveTrackingItemUnsafe(TrackingItem trackingItem) + protected Task SaveTrackingItemUnsafe(TrackingItem trackingItem) => SaveItemUnsafe(trackingItem.CurrentValue, trackingItem.TrackingState); - protected Task SaveTrackingItemUnsafeAsync(TrackingItem trackingItem) + protected Task SaveTrackingItemUnsafeAsync(TrackingItem trackingItem) => SaveItemUnsafeAsync(trackingItem.CurrentValue, trackingItem.TrackingState); - protected Task SaveItemUnsafe(T item, TrackingState trackingState) + protected Task SaveItemUnsafe(TDataItem item, TrackingState trackingState) { var messageTag = SignalRCrudTags.GetMessageTagByTrackingState(trackingState); if (messageTag == AcSignalRTags.None) throw new ArgumentException($"SaveItemUnsafe; messageTag == SignalRTags.None"); @@ -744,7 +854,7 @@ namespace AyCode.Services.Server.SignalRs }); } - protected Task SaveItemUnsafeAsync(T item, TrackingState trackingState) + protected Task SaveItemUnsafeAsync(TDataItem item, TrackingState trackingState) { var messageTag = SignalRCrudTags.GetMessageTagByTrackingState(trackingState); if (messageTag == AcSignalRTags.None) return Task.CompletedTask; @@ -771,7 +881,7 @@ namespace AyCode.Services.Server.SignalRs }); } - private Task ProcessSavedResponseItem(T? resultItem, TrackingState trackingState) + private Task ProcessSavedResponseItem(TDataItem? resultItem, TrackingState trackingState) { if (resultItem == null) return Task.CompletedTask; @@ -781,13 +891,13 @@ namespace AyCode.Services.Server.SignalRs if (TryGetIndex(resultItem.Id, out var index)) InnerList[index] = resultItem; - var eventArgs = new ItemChangedEventArgs(resultItem, trackingState); + var eventArgs = new ItemChangedEventArgs(resultItem, trackingState); if (OnDataSourceItemChanged != null) return OnDataSourceItemChanged.Invoke(eventArgs); return Task.CompletedTask; } - protected void RollbackItemUnsafe(TrackingItem trackingItem) + protected void RollbackItemUnsafe(TrackingItem trackingItem) { if (TryGetIndex(trackingItem.CurrentValue.Id, out var index)) { @@ -800,7 +910,7 @@ namespace AyCode.Services.Server.SignalRs TrackingItems.Remove(trackingItem); } - public bool TryRollbackItem(Guid id, out T? originalValue) + public bool TryRollbackItem(TId id, out TDataItem? originalValue) { Monitor.Enter(_syncRoot); try @@ -869,12 +979,12 @@ namespace AyCode.Services.Server.SignalRs } } - public int IndexOf(Guid id) + public int IndexOf(TId id) { Monitor.Enter(_syncRoot); try { - return InnerList.FindIndex(x => x.Id == id); + return FindIndexInnerList(id); } finally { @@ -883,17 +993,17 @@ namespace AyCode.Services.Server.SignalRs } - public int IndexOf(T item) => IndexOf(item.Id); - public bool TryGetIndex(Guid id, out int index) => (index = IndexOf(id)) > -1; + public int IndexOf(TDataItem item) => IndexOf(item.Id); + public bool TryGetIndex(TId id, out int index) => (index = IndexOf(id)) > -1; - public bool Contains(T item) => IndexOf(item) > -1; + public bool Contains(TDataItem item) => IndexOf(item) > -1; - public bool TryGetValue(Guid id, [NotNullWhen(true)] out T? item) + public bool TryGetValue(TId id, [NotNullWhen(true)] out TDataItem? item) { Monitor.Enter(_syncRoot); try { - item = InnerList.FirstOrDefault(x => x.Id == id); + item = FirstOrDefaultInnerList(id);//InnerList.FirstOrDefault(x => x.Id == id); return item != null; } finally @@ -902,9 +1012,9 @@ namespace AyCode.Services.Server.SignalRs } } - public void CopyTo(T[] array) => CopyTo(array, 0); + public void CopyTo(TDataItem[] array) => CopyTo(array, 0); - public void CopyTo(T[] array, int arrayIndex) + public void CopyTo(TDataItem[] array, int arrayIndex) { Monitor.Enter(_syncRoot); try @@ -918,7 +1028,7 @@ namespace AyCode.Services.Server.SignalRs } - public int BinarySearch(int index, int count, T item, IComparer? comparer) + public int BinarySearch(int index, int count, TDataItem item, IComparer? comparer) { throw new NotImplementedException($"BinarySearch"); if (index < 0) @@ -939,10 +1049,10 @@ namespace AyCode.Services.Server.SignalRs //} } - public int BinarySearch(T item) => BinarySearch(0, Count, item, null); - public int BinarySearch(T item, IComparer? comparer) => BinarySearch(0, Count, item, comparer); + public int BinarySearch(TDataItem item) => BinarySearch(0, Count, item, null); + public int BinarySearch(TDataItem item, IComparer? comparer) => BinarySearch(0, Count, item, comparer); - public IEnumerator GetEnumerator() + public IEnumerator GetEnumerator() { Monitor.Enter(_syncRoot); try @@ -957,8 +1067,8 @@ namespace AyCode.Services.Server.SignalRs } - public ReadOnlyCollection AsReadOnly() => new(this); - private static bool IsCompatibleObject(object? value) => (value is T) || (value == null && default(T) == null); + public ReadOnlyCollection AsReadOnly() => new(this); + private static bool IsCompatibleObject(object? value) => (value is TDataItem) || (value == null && default(TDataItem) == null); #region IList, ICollection @@ -970,11 +1080,11 @@ namespace AyCode.Services.Server.SignalRs get => this[index]; set { - if (default(T) != null && value == null) throw new NullReferenceException(nameof(value)); + if (default(TDataItem) != null && value == null) throw new NullReferenceException(nameof(value)); try { - this[index] = (T)value!; + this[index] = (TDataItem)value!; } catch (InvalidCastException) { @@ -985,11 +1095,11 @@ namespace AyCode.Services.Server.SignalRs int IList.Add(object? item) { - if (default(T) != null && item == null) throw new NullReferenceException(nameof(item)); + if (default(TDataItem) != null && item == null) throw new NullReferenceException(nameof(item)); try { - Add((T)item!); + Add((TDataItem)item!); } catch (InvalidCastException) { @@ -1001,16 +1111,16 @@ namespace AyCode.Services.Server.SignalRs void IList.Clear() => Clear(true); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - bool IList.Contains(object? item) => IsCompatibleObject(item) && Contains((T)item!); - int IList.IndexOf(object? item) => (IsCompatibleObject(item)) ? IndexOf((T)item!) : -1; + bool IList.Contains(object? item) => IsCompatibleObject(item) && Contains((TDataItem)item!); + int IList.IndexOf(object? item) => (IsCompatibleObject(item)) ? IndexOf((TDataItem)item!) : -1; void IList.Insert(int index, object? item) { - if (default(T) != null && item == null) throw new NullReferenceException(nameof(item)); + if (default(TDataItem) != null && item == null) throw new NullReferenceException(nameof(item)); try { - Insert(index, (T)item!); + Insert(index, (TDataItem)item!); } catch (InvalidCastException) { @@ -1020,10 +1130,10 @@ namespace AyCode.Services.Server.SignalRs void IList.Remove(object? item) { - if (IsCompatibleObject(item)) Remove((T)item!); + if (IsCompatibleObject(item)) Remove((TDataItem)item!); } - void ICollection.Clear() => Clear(true); + void ICollection.Clear() => Clear(true); void ICollection.CopyTo(Array array, int arrayIndex) { @@ -1053,15 +1163,15 @@ namespace AyCode.Services.Server.SignalRs } int ICollection.Count => Count; - int ICollection.Count => Count; - bool ICollection.IsReadOnly => false; - void IList.RemoveAt(int index) => RemoveAt(index); - int IReadOnlyCollection.Count => Count; + int ICollection.Count => Count; + bool ICollection.IsReadOnly => false; + void IList.RemoveAt(int index) => RemoveAt(index); + int IReadOnlyCollection.Count => Count; #endregion IList, ICollection } - public class ItemChangedEventArgs where T : IId + public class ItemChangedEventArgs where T : class { internal ItemChangedEventArgs(T item, TrackingState trackingState) {