Skip to content

Commit 1b37405

Browse files
committed
!3788 feat(#I6B6FB): add IModelEqualityComparer interface for reuse compare model
* refactor: rename IModelEqualityComparer extension * refactor: use IModelEqualityComparer interface for code reuse * fix: update code for Equals parameter * refactor: add nullable constraint * refactor: remove suggesion * refactor: add IModelEqualityComparer interface * refactor: change _itemCache to ItemCache * refactor: update Equlas check logic make it faster * refactor: update ModelComparer make it simple
1 parent 6461849 commit 1b37405

15 files changed

Lines changed: 143 additions & 87 deletions

src/BootstrapBlazor/Components/Select/SelectTree.razor.cs

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ namespace BootstrapBlazor.Components;
1111
/// </summary>
1212
/// <typeparam name="TValue"></typeparam>
1313
[JSModuleAutoLoader("select-tree")]
14-
public partial class SelectTree<TValue>
14+
public partial class SelectTree<TValue> : IModelEqualityComparer<TValue>
1515
{
1616
/// <summary>
1717
/// 获得 样式集合
@@ -120,17 +120,17 @@ public partial class SelectTree<TValue>
120120

121121
private TreeViewItem<TValue>? SelectedItem { get; set; }
122122

123-
private List<TreeViewItem<TValue>>? _itemCache;
123+
private List<TreeViewItem<TValue>>? ItemCache { get; set; }
124124

125125
[NotNull]
126126
private List<TreeViewItem<TValue>>? ExpansionItemsCache { get; set; }
127127

128128
private IEnumerable<TreeViewItem<TValue>> GetExpansionItems()
129129
{
130-
if (_itemCache != Items)
130+
if (ItemCache != Items)
131131
{
132-
_itemCache = Items ?? new List<TreeViewItem<TValue>>();
133-
ExpansionItemsCache = TreeItemExtensions.GetAllItems(_itemCache).ToList();
132+
ItemCache = Items ?? new List<TreeViewItem<TValue>>();
133+
ExpansionItemsCache = TreeItemExtensions.GetAllItems(ItemCache).ToList();
134134
}
135135
return ExpansionItemsCache;
136136
}
@@ -147,7 +147,7 @@ protected override async Task OnParametersSetAsync()
147147

148148
if (Value != null)
149149
{
150-
var currentItem = GetExpansionItems().FirstOrDefault(s => ComparerItem(s.Value, Value));
150+
var currentItem = GetExpansionItems().FirstOrDefault(s => Equals(s.Value, Value));
151151
if (currentItem != null)
152152
{
153153
SelectedItem = currentItem;
@@ -192,12 +192,8 @@ private async Task ItemChanged(TreeViewItem<TValue> item)
192192
/// <summary>
193193
/// 比较数据是否相同
194194
/// </summary>
195-
/// <param name="a"></param>
196-
/// <param name="b"></param>
195+
/// <param name="x"></param>
196+
/// <param name="y"></param>
197197
/// <returns></returns>
198-
protected bool ComparerItem(TValue a, TValue b) => ModelEqualityComparer?.Invoke(a, b)
199-
?? Utility.GetKeyValue<TValue, object>(a, CustomKeyAttribute)?.Equals(Utility.GetKeyValue<TValue, object>(b, CustomKeyAttribute))
200-
?? ModelComparer.EqualityComparer(a, b)
201-
?? a?.Equals(b)
202-
?? false;
198+
public bool Equals(TValue? x, TValue? y) => this.Equals<TValue>(x, y);
203199
}

src/BootstrapBlazor/Components/Table/Table.razor.Checkbox.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,15 +42,15 @@ protected CheckboxState HeaderCheckState()
4242
}
4343
return ret;
4444

45-
bool AnyRow(TItem row) => SelectedRows.Any(i => ComparerItem(i, row));
45+
bool AnyRow(TItem row) => SelectedRows.Any(i => Equals(i, row));
4646
}
4747

4848
/// <summary>
4949
/// 获得 当前行是否被选中
5050
/// </summary>
5151
/// <param name="item"></param>
5252
/// <returns></returns>
53-
protected CheckboxState RowCheckState(TItem item) => SelectedRows.Any(i => ComparerItem(i, item)) ? CheckboxState.Checked : CheckboxState.UnChecked;
53+
protected CheckboxState RowCheckState(TItem item) => SelectedRows.Any(i => Equals(i, item)) ? CheckboxState.Checked : CheckboxState.UnChecked;
5454

5555
/// <summary>
5656
/// 获得/设置 是否为多选模式 默认为 false
@@ -109,7 +109,7 @@ protected async Task OnCheck(CheckboxState state, TItem val)
109109
}
110110
else
111111
{
112-
var item = SelectedRows.FirstOrDefault(i => ComparerItem(i, val));
112+
var item = SelectedRows.FirstOrDefault(i => Equals(i, val));
113113
if (item != null)
114114
{
115115
SelectedRows.Remove(item);

src/BootstrapBlazor/Components/Table/Table.razor.Edit.cs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -546,16 +546,12 @@ private QueryPageOptions BuildQueryPageOptions()
546546
return queryOption;
547547
}
548548

549-
private void ResetSelectedRows(IEnumerable<TItem> items) => SelectedRows = items.Where(i => SelectedRows.Any(row => ComparerItem(i, row))).ToList();
549+
private void ResetSelectedRows(IEnumerable<TItem> items) => SelectedRows = items.Where(i => SelectedRows.Any(row => Equals(i, row))).ToList();
550550

551551
/// <summary>
552552
/// <inheritdoc/>
553553
/// </summary>
554-
public bool ComparerItem(TItem a, TItem b) => ModelEqualityComparer?.Invoke(a, b)
555-
?? DynamicContext?.EqualityComparer?.Invoke((IDynamicObject)a, (IDynamicObject)b)
556-
?? Utility.GetKeyValue<TItem, object>(a, CustomKeyAttribute)?.Equals(Utility.GetKeyValue<TItem, object>(b, CustomKeyAttribute))
557-
?? ModelComparer.EqualityComparer(a, b)
558-
?? a.Equals(b);
554+
public bool Equals(TItem? x, TItem? y) => DynamicContext?.EqualityComparer?.Invoke((IDynamicObject?)x, (IDynamicObject?)y) ?? this.Equals<TItem>(x, y);
559555

560556
private async Task OnClickExtensionButton(TItem item, TableCellButtonArgs args)
561557
{

src/BootstrapBlazor/Components/Table/Table.razor.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ namespace BootstrapBlazor.Components;
1515
[CascadingTypeParameter(nameof(TItem))]
1616
#endif
1717
[JSModuleAutoLoader(JSObjectReference = true)]
18-
public partial class Table<TItem> : ITable where TItem : class, new()
18+
public partial class Table<TItem> : ITable, IModelEqualityComparer<TItem> where TItem : class, new()
1919
{
2020
/// <summary>
2121
/// 获得/设置 内置虚拟化组件实例
@@ -543,7 +543,7 @@ protected override void OnInitialized()
543543
base.OnInitialized();
544544

545545
// 初始化节点缓存
546-
treeNodeCache ??= new(ComparerItem);
546+
treeNodeCache ??= new(Equals);
547547

548548
OnInitLocalization();
549549

src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ namespace BootstrapBlazor.Components;
1212
#if NET6_0_OR_GREATER
1313
[CascadingTypeParameter(nameof(TItem))]
1414
#endif
15-
public partial class TreeView<TItem>
15+
public partial class TreeView<TItem> : IModelEqualityComparer<TItem>
1616
{
1717
/// <summary>
1818
/// 获得/设置 Tree 组件实例引用
@@ -198,7 +198,7 @@ protected override void OnInitialized()
198198
base.OnInitialized();
199199

200200
// 初始化节点缓存
201-
treeNodeCache ??= new(ComparerItem);
201+
treeNodeCache ??= new(Equals);
202202
NotSetOnTreeExpandErrorMessage = Localizer[nameof(NotSetOnTreeExpandErrorMessage)];
203203
}
204204

@@ -423,12 +423,8 @@ public IEnumerable<TreeViewItem<TItem>> GetCheckedItems() => Items.Aggregate(new
423423
/// <summary>
424424
/// 比较数据是否相同
425425
/// </summary>
426-
/// <param name="a"></param>
427-
/// <param name="b"></param>
426+
/// <param name="x"></param>
427+
/// <param name="y"></param>
428428
/// <returns></returns>
429-
protected bool ComparerItem(TItem a, TItem b) => ModelEqualityComparer?.Invoke(a, b)
430-
?? Utility.GetKeyValue<TItem, object>(a, CustomKeyAttribute)?.Equals(Utility.GetKeyValue<TItem, object>(b, CustomKeyAttribute))
431-
?? ModelComparer.EqualityComparer(a, b)
432-
?? a?.Equals(b)
433-
?? false;
429+
public bool Equals(TItem? x, TItem? y) => this.Equals<TItem>(x, y);
434430
}

src/BootstrapBlazor/Dynamic/DataTableDynamicContext.cs

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -70,11 +70,7 @@ public DataTableDynamicContext(DataTable table, Action<DataTableDynamicContext,
7070
Type CreateType()
7171
{
7272
var dynamicType = EmitHelper.CreateTypeByName($"BootstrapBlazor_{nameof(DataTableDynamicContext)}_{GetHashCode()}", cols, typeof(DataTableDynamicObject), OnColumnCreating);
73-
if (dynamicType == null)
74-
{
75-
throw new InvalidOperationException();
76-
}
77-
return dynamicType;
73+
return dynamicType ?? throw new InvalidOperationException();
7874
}
7975
}
8076

@@ -215,10 +211,7 @@ public override async Task AddAsync(IEnumerable<IDynamicObject> selectedItems)
215211
}
216212

217213
// Table 组件数据源更新数据
218-
if (Items != null)
219-
{
220-
Items.Insert(indexOfRow, dynamicObject);
221-
}
214+
Items?.Insert(indexOfRow, dynamicObject);
222215

223216
// 缓存更新数据
224217
Caches.TryAdd(dynamicObject.DynamicObjectPrimaryKey, (dynamicObject, row));
@@ -236,10 +229,7 @@ public override async Task<bool> DeleteAsync(IEnumerable<IDynamicObject> items)
236229
if (OnDeleteAsync != null)
237230
{
238231
ret = await OnDeleteAsync(items);
239-
if (Items != null)
240-
{
241-
Items.RemoveAll(i => items.Any(item => item == i));
242-
}
232+
Items?.RemoveAll(i => items.Any(item => item == i));
243233
}
244234
else
245235
{
@@ -257,10 +247,7 @@ public override async Task<bool> DeleteAsync(IEnumerable<IDynamicObject> items)
257247
Caches.TryRemove(item.DynamicObjectPrimaryKey, out _);
258248

259249
// 清理 Table 组件数据源
260-
if (Items != null)
261-
{
262-
Items.Remove(item);
263-
}
250+
Items?.Remove(item);
264251
}
265252
}
266253
if (changed)

src/BootstrapBlazor/Dynamic/DynamicObjectContext.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,5 +93,5 @@ protected internal virtual IEnumerable<CustomAttributeBuilder> OnColumnCreating(
9393
/// <summary>
9494
/// 获得选中行比对回调方法
9595
/// </summary>
96-
public Func<IDynamicObject, IDynamicObject, bool>? EqualityComparer { get; set; }
96+
public Func<IDynamicObject?, IDynamicObject?, bool>? EqualityComparer { get; set; }
9797
}

src/BootstrapBlazor/Dynamic/IDynamicObjectContext.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,5 +49,5 @@ public interface IDynamicObjectContext
4949
/// <summary>
5050
/// 获得/设置 选中行是否相等判断逻辑 默认为 null
5151
/// </summary>
52-
Func<IDynamicObject, IDynamicObject, bool>? EqualityComparer { get; set; }
52+
Func<IDynamicObject?, IDynamicObject?, bool>? EqualityComparer { get; set; }
5353
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
// Website: https://www.blazor.zone or https://argozhang.github.io/
4+
5+
namespace BootstrapBlazor.Components;
6+
7+
/// <summary>
8+
/// IModelEqualComparer 扩展方法类
9+
/// </summary>
10+
public static class IModelEqualityComparerExtensions
11+
{
12+
/// <summary>
13+
/// Equals 扩展方法
14+
/// </summary>
15+
/// <typeparam name="TItem"></typeparam>
16+
/// <param name="comparer"></param>
17+
/// <param name="x"></param>
18+
/// <param name="y"></param>
19+
/// <returns></returns>
20+
public static bool Equals<TItem>(this IModelEqualityComparer<TItem> comparer, TItem? x, TItem? y)
21+
{
22+
bool ret;
23+
if (x == null && y == null)
24+
{
25+
ret = true;
26+
}
27+
else if (x == null || y == null)
28+
{
29+
ret = false;
30+
}
31+
else
32+
{
33+
ret = comparer.ModelEqualityComparer?.Invoke(x, y)
34+
?? Utility.GetKeyValue<TItem, object>(x, comparer.CustomKeyAttribute)?.Equals(Utility.GetKeyValue<TItem, object>(y, comparer.CustomKeyAttribute))
35+
?? EqualityComparer();
36+
}
37+
return ret;
38+
39+
bool EqualityComparer()
40+
{
41+
bool ret;
42+
if (x is IEqualityComparer<TItem> comparer)
43+
{
44+
// 显式调用 IEqualityComparer 接口的 Equals 方法
45+
ret = comparer.Equals(x, y);
46+
}
47+
else
48+
{
49+
// 调用 Object 对象的 Equlas 方法
50+
ret = x.Equals(y);
51+
}
52+
return ret;
53+
}
54+
}
55+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
// Website: https://www.blazor.zone or https://argozhang.github.io/
4+
5+
namespace BootstrapBlazor.Components;
6+
7+
/// <summary>
8+
/// 模型比较接口
9+
/// </summary>
10+
public interface IModelEqualityComparer<TItem>
11+
{
12+
/// <summary>
13+
///
14+
/// </summary>
15+
Func<TItem, TItem, bool>? ModelEqualityComparer { get; set; }
16+
17+
/// <summary>
18+
///
19+
/// </summary>
20+
Type CustomKeyAttribute { get; set; }
21+
22+
/// <summary>
23+
///
24+
/// </summary>
25+
/// <param name="x"></param>
26+
/// <param name="y"></param>
27+
/// <returns></returns>
28+
bool Equals(TItem? x, TItem? y);
29+
}

0 commit comments

Comments
 (0)