Skip to content

Commit 6ac961e

Browse files
authored
feat(EmitHelper): use cache to reduce dynamic type creation. (#7797)
* doc: 更新用法文档 * doc: 增加提示信息 * refactor: 移除已弃用参数 * refactor: 重命名缓存变量 * feat: 增加缓存防止生成过多动态类型 * doc: 更新示例 * chore: bump version 10.5.0-beta02 * refactor: 增加 readonly 关键字
1 parent 5270336 commit 6ac961e

File tree

4 files changed

+40
-12
lines changed

4 files changed

+40
-12
lines changed

src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamic.razor.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ private void CreateContext()
4747
DataTableDynamicContext = new DataTableDynamicContext(UserData, (context, col) =>
4848
{
4949
var propertyName = col.GetFieldName();
50+
// 使用 Text 设置显示名称示例
51+
col.Text = FooLocalizer[propertyName];
5052
if (propertyName == nameof(Foo.DateTime))
5153
{
5254
context.AddRequiredAttribute(nameof(Foo.DateTime));
@@ -56,8 +58,6 @@ private void CreateContext()
5658
else if (propertyName == nameof(Foo.Name))
5759
{
5860
context.AddRequiredAttribute(nameof(Foo.Name), FooLocalizer["Name.Required"]);
59-
// 使用 Text 设置显示名称示例
60-
col.Text = FooLocalizer[nameof(Foo.Name)];
6161
}
6262
else if (propertyName == nameof(Foo.Count))
6363
{

src/BootstrapBlazor/BootstrapBlazor.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk.Razor">
22

33
<PropertyGroup>
4-
<Version>10.5.0-beta01</Version>
4+
<Version>10.5.0-beta02</Version>
55
</PropertyGroup>
66

77
<ItemGroup>

src/BootstrapBlazor/Dynamic/DataTableDynamicContext.cs

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public class DataTableDynamicContext : DynamicObjectContext
4040
/// <para lang="zh">负责将 DataRow 与 Items 关联起来方便查找提高效率</para>
4141
/// <para lang="en">Responsible for associating DataRow with Items to facilitate lookup and improve efficiency</para>
4242
/// </summary>
43-
private ConcurrentDictionary<Guid, (IDynamicObject DynamicObject, DataRow Row)> Caches { get; } = new();
43+
private readonly ConcurrentDictionary<Guid, (IDynamicObject DynamicObject, DataRow Row)> _dataCache = new();
4444

4545
/// <summary>
4646
/// <para lang="zh">添加行回调委托</para>
@@ -90,7 +90,20 @@ public DataTableDynamicContext(DataTable table, Action<DataTableDynamicContext,
9090
[ExcludeFromCodeCoverage]
9191
Type CreateType()
9292
{
93-
var dynamicType = EmitHelper.CreateTypeByName($"BootstrapBlazor_{nameof(DataTableDynamicContext)}_{GetHashCode()}", cols, typeof(DataTableDynamicObject), OnColumnCreating);
93+
// Emit 生成动态类 (使用缓存)
94+
var columnNames = string.Join('|', table.Columns.Cast<DataColumn>().Select(static c => $"{c.ColumnName}:{c.DataType.FullName}"));
95+
var cacheKey = $"BootstrapBlazor-{nameof(DataTableDynamicContext)}-{columnNames}";
96+
var dynamicType = CacheManager.GetDynamicObjectTypeByName(cacheKey, cols, OnColumnCreating, out var cached);
97+
98+
// 缓存命中时仍需调用回调以处理列属性
99+
if (cached && AddAttributesCallback != null)
100+
{
101+
foreach (var col in cols)
102+
{
103+
AddAttributesCallback?.Invoke(this, col);
104+
}
105+
}
106+
94107
return dynamicType ?? throw new InvalidOperationException();
95108
}
96109
}
@@ -136,7 +149,7 @@ public override IEnumerable<IDynamicObject> GetItems()
136149

137150
private List<IDynamicObject> BuildItems()
138151
{
139-
Caches.Clear();
152+
_dataCache.Clear();
140153
var ret = new List<IDynamicObject>();
141154
foreach (DataRow row in DataTable.Rows)
142155
{
@@ -155,7 +168,7 @@ private List<IDynamicObject> BuildItems()
155168

156169
d.Row = row;
157170
d.DynamicObjectPrimaryKey = Guid.NewGuid();
158-
Caches.TryAdd(d.DynamicObjectPrimaryKey, (d, row));
171+
_dataCache.TryAdd(d.DynamicObjectPrimaryKey, (d, row));
159172
ret.Add(d);
160173
}
161174
}
@@ -203,7 +216,7 @@ public override async Task AddAsync(IEnumerable<IDynamicObject> selectedItems)
203216
var indexOfRow = 0;
204217
var item = selectedItems.FirstOrDefault();
205218

206-
if (item != null && Caches.TryGetValue(item.DynamicObjectPrimaryKey, out var c))
219+
if (item != null && _dataCache.TryGetValue(item.DynamicObjectPrimaryKey, out var c))
207220
{
208221
indexOfRow = DataTable.Rows.IndexOf(c.Row);
209222
}
@@ -232,7 +245,7 @@ public override async Task AddAsync(IEnumerable<IDynamicObject> selectedItems)
232245
Items?.Insert(indexOfRow, dynamicObject);
233246

234247
// 缓存更新数据
235-
Caches.TryAdd(dynamicObject.DynamicObjectPrimaryKey, (dynamicObject, row));
248+
_dataCache.TryAdd(dynamicObject.DynamicObjectPrimaryKey, (dynamicObject, row));
236249
}
237250
}
238251

@@ -252,15 +265,15 @@ public override async Task<bool> DeleteAsync(IEnumerable<IDynamicObject> items)
252265
var changed = false;
253266
foreach (var item in items)
254267
{
255-
if (Caches.TryGetValue(item.DynamicObjectPrimaryKey, out var row))
268+
if (_dataCache.TryGetValue(item.DynamicObjectPrimaryKey, out var row))
256269
{
257270
changed = true;
258271

259272
// 删除数据源
260273
DataTable.Rows.Remove(row.Row);
261274

262275
// 清理缓存
263-
Caches.TryRemove(item.DynamicObjectPrimaryKey, out _);
276+
_dataCache.TryRemove(item.DynamicObjectPrimaryKey, out _);
264277

265278
// 清理 Table 组件数据源
266279
Items?.Remove(item);
@@ -289,7 +302,7 @@ public override async Task<bool> DeleteAsync(IEnumerable<IDynamicObject> items)
289302
private Task OnCellValueChanged(IDynamicObject item, ITableColumn column, object? val)
290303
{
291304
// 更新内部 DataRow
292-
if (Caches.TryGetValue(item.DynamicObjectPrimaryKey, out var cacheItem))
305+
if (_dataCache.TryGetValue(item.DynamicObjectPrimaryKey, out var cacheItem))
293306
{
294307
cacheItem.Row[column.GetFieldName()] = val;
295308
Items = null;

src/BootstrapBlazor/Services/CacheManager.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
using System.Globalization;
1111
using System.Linq.Expressions;
1212
using System.Reflection;
13+
using System.Reflection.Emit;
1314

1415
#if NET8_0_OR_GREATER
1516
using System.Runtime.CompilerServices;
@@ -764,4 +765,18 @@ public static object GetFormatterInvoker(Type type, Func<object, Task<string?>>
764765

765766
private static Func<TType, Task<string?>> InvokeFormatterAsync<TType>(Func<object?, Task<string?>> formatter) => new(v => formatter(v));
766767
#endregion
768+
769+
internal static Type? GetDynamicObjectTypeByName(string key, IEnumerable<ITableColumn> cols, Func<ITableColumn, IEnumerable<CustomAttributeBuilder>>? creatingCallback, out bool cached)
770+
{
771+
var created = false;
772+
var type = Instance.GetOrCreate(key, _ =>
773+
{
774+
created = true;
775+
return EmitHelper.CreateTypeByName($"BootstrapBlazor_{nameof(DataTableDynamicContext)}_{key}", cols, typeof(DataTableDynamicObject), creatingCallback);
776+
});
777+
778+
// 是否从缓存中获取到的值
779+
cached = !created;
780+
return type;
781+
}
767782
}

0 commit comments

Comments
 (0)