diff --git a/src/BootstrapBlazor/BootstrapBlazor.csproj b/src/BootstrapBlazor/BootstrapBlazor.csproj index 90a61c17663..e4ca825a58a 100644 --- a/src/BootstrapBlazor/BootstrapBlazor.csproj +++ b/src/BootstrapBlazor/BootstrapBlazor.csproj @@ -1,7 +1,7 @@  - 9.4.5 + 9.4.6 diff --git a/src/BootstrapBlazor/Components/Table/Table.razor.Edit.cs b/src/BootstrapBlazor/Components/Table/Table.razor.Edit.cs index 33343ab736b..fa8b766812e 100644 --- a/src/BootstrapBlazor/Components/Table/Table.razor.Edit.cs +++ b/src/BootstrapBlazor/Components/Table/Table.razor.Edit.cs @@ -294,18 +294,28 @@ private async Task InternalOnAddAsync() [Parameter] public Func? CreateItemCallback { get; set; } + /// + /// Get or sets Whether to automatically initialize model properties default value is false. + /// + [Parameter] + public bool IsAutoInitializeModelProperty { get; set; } + private TItem CreateTItem() => CreateItemCallback?.Invoke() ?? CreateInstance(); + private readonly string ErrorMessage = $"{typeof(TItem)} create instrance failed. Please provide {nameof(CreateItemCallback)} create the {typeof(TItem)} instance. {typeof(TItem)} 自动创建实例失败,请通过 {nameof(CreateItemCallback)} 回调方法手动创建实例"; + private TItem CreateInstance() { + TItem? item; try { - return ObjectExtensions.CreateInstanceWithCascade(); + item = ObjectExtensions.CreateInstance(IsAutoInitializeModelProperty); } catch (Exception ex) { - throw new InvalidOperationException($"{typeof(TItem)} missing new() method. Please provide {nameof(CreateItemCallback)} create the {typeof(TItem)} instance. {typeof(TItem)} 未提供无参构造函数 new() 请通过 {nameof(CreateItemCallback)} 回调方法创建实例", ex); + throw new InvalidOperationException(ErrorMessage, ex); } + return item!; } /// diff --git a/src/BootstrapBlazor/Extensions/ObjectExtensions.cs b/src/BootstrapBlazor/Extensions/ObjectExtensions.cs index 637e0db9f6a..d631022682c 100644 --- a/src/BootstrapBlazor/Extensions/ObjectExtensions.cs +++ b/src/BootstrapBlazor/Extensions/ObjectExtensions.cs @@ -242,20 +242,40 @@ internal static void Clone(this TModel source, TModel item) /// Creates an instance of a type and ensures all class-type properties are initialized. /// /// The type to create an instance of. + /// Whether to automatically initialize model properties default value is false. /// An instance of the specified type with initialized properties. - public static TItem CreateInstanceWithCascade() + public static TItem? CreateInstance(bool isAutoInitializeModelProperty = false) { var instance = Activator.CreateInstance(); - instance!.EnsureInitialized(); + if (isAutoInitializeModelProperty) + { + instance.EnsureInitialized(isAutoInitializeModelProperty); + } + return instance; + } + + private static object? CreateInstance(Type type, bool isAutoInitializeModelProperty = false) + { + var instance = Activator.CreateInstance(type); + if (isAutoInitializeModelProperty) + { + instance.EnsureInitialized(); + } return instance; } /// /// Ensures that all class-type properties of the instance are initialized. /// + /// Whether to automatically initialize model properties default value is false. /// The instance to initialize properties for. - private static void EnsureInitialized(this object instance) + private static void EnsureInitialized(this object? instance, bool isAutoInitializeModelProperty = false) { + if (instance is null) + { + return; + } + // Reflection performance needs to be optimized here foreach (var propertyInfo in instance.GetType().GetProperties().Where(p => p.PropertyType.IsClass && p.PropertyType != typeof(string))) { @@ -263,16 +283,12 @@ private static void EnsureInitialized(this object instance) var value = propertyInfo.GetValue(instance, null); if (value is null) { - var pv = CreateInstance(type); - propertyInfo.SetValue(instance, pv); + var pv = CreateInstance(type, isAutoInitializeModelProperty); + if (pv is not null) + { + propertyInfo.SetValue(instance, pv); + } } } } - - private static object? CreateInstance(Type type) - { - var instance = Activator.CreateInstance(type); - instance!.EnsureInitialized(); - return instance; - } } diff --git a/test/UnitTest/Components/TableTest.cs b/test/UnitTest/Components/TableTest.cs index b20df021baa..54527fb6684 100644 --- a/test/UnitTest/Components/TableTest.cs +++ b/test/UnitTest/Components/TableTest.cs @@ -127,6 +127,7 @@ public async Task Items_Add(InsertRowMode insertMode, bool bind) { pb.AddChildContent>(pb => { + pb.Add(a => a.IsAutoInitializeModelProperty, true); pb.Add(a => a.Items, items); if (bind) { diff --git a/test/UnitTest/Extensions/ObjectExtensionsTest.cs b/test/UnitTest/Extensions/ObjectExtensionsTest.cs index 74d6aeded7f..90beda9ef93 100644 --- a/test/UnitTest/Extensions/ObjectExtensionsTest.cs +++ b/test/UnitTest/Extensions/ObjectExtensionsTest.cs @@ -303,6 +303,27 @@ public void IsStatic_Ok() Assert.True(pi.IsStatic()); } + [Fact] + public void CreateInstance_Ok() + { + var exception = Assert.ThrowsAny(() => ObjectExtensions.CreateInstance(true)); + + var mi = typeof(ObjectExtensions).GetMethod("EnsureInitialized", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic); + Assert.NotNull(mi); + mi.Invoke(null, [null, false]); + + var instance = ObjectExtensions.CreateInstance(false); + Assert.NotNull(instance); + Assert.Null(instance.Test); + } + + private class MockComplexObject + { + public Foo? Foo { get; set; } + + public (string Name, int Count)[]? Test { get; set; } + } + private class MockStatic { private static int _test;