Browse Source

add ObjectHelper support for property resolution for value types

pull/18970/head
namtab00 3 years ago
committed by Stefan Anghel
parent
commit
ab188c6dc8
  1. 47
      framework/src/Volo.Abp.Core/Volo/Abp/ObjectHelper.cs
  2. 35
      framework/test/Volo.Abp.Core.Tests/Volo/Abp/ObjectHelper_Tests.cs

47
framework/src/Volo.Abp.Core/Volo/Abp/ObjectHelper.cs

@ -9,8 +9,7 @@ namespace Volo.Abp;
public static class ObjectHelper
{
private static readonly ConcurrentDictionary<string, PropertyInfo?> CachedObjectProperties =
new ConcurrentDictionary<string, PropertyInfo?>();
private static readonly ConcurrentDictionary<string, PropertyInfo?> _cachedObjectProperties = new();
public static void TrySetProperty<TObject, TValue>(
TObject obj,
@ -27,37 +26,53 @@ public static class ObjectHelper
Func<TObject, TValue> valueFactory,
params Type[]? ignoreAttributeTypes)
{
var cacheKey = $"{obj?.GetType().FullName}-" +
$"{propertySelector}-" +
$"{(ignoreAttributeTypes != null ? "-" + string.Join("-", ignoreAttributeTypes.Select(x => x.FullName)) : "")}";
var cacheKey =
$"{obj?.GetType().FullName}-{propertySelector}-{(ignoreAttributeTypes != null ? "-" + string.Join("-", ignoreAttributeTypes.Select(x => x.FullName)) : "")}";
var property = CachedObjectProperties.GetOrAdd(cacheKey, () =>
var property = _cachedObjectProperties.GetOrAdd(cacheKey, PropertyFactory);
property?.SetValue(obj, valueFactory(obj));
return;
PropertyInfo? PropertyFactory(string _)
{
if (propertySelector.Body.NodeType != ExpressionType.MemberAccess)
MemberExpression? memberExpression;
switch (propertySelector.Body.NodeType)
{
case ExpressionType.Convert: {
memberExpression = propertySelector.Body.As<UnaryExpression>().Operand as MemberExpression;
break;
}
case ExpressionType.MemberAccess: {
memberExpression = propertySelector.Body.As<MemberExpression>();
break;
}
default: {
return null;
}
}
if (memberExpression == null)
{
return null;
}
var memberExpression = propertySelector.Body.As<MemberExpression>();
var propertyInfo = obj?.GetType().GetProperties().FirstOrDefault(x =>
x.Name == memberExpression.Member.Name &&
x.GetSetMethod(true) != null);
var propertyInfo = obj?.GetType()
.GetProperties()
.FirstOrDefault(x => x.Name == memberExpression.Member.Name && x.GetSetMethod(true) != null);
if (propertyInfo == null)
{
return null;
}
if (ignoreAttributeTypes != null &&
ignoreAttributeTypes.Any(ignoreAttribute => propertyInfo.IsDefined(ignoreAttribute, true)))
if (ignoreAttributeTypes != null && ignoreAttributeTypes.Any(ignoreAttribute => propertyInfo.IsDefined(ignoreAttribute, true)))
{
return null;
}
return propertyInfo;
});
property?.SetValue(obj, valueFactory(obj));
}
}
}

35
framework/test/Volo.Abp.Core.Tests/Volo/Abp/ObjectHelper_Tests.cs

@ -39,6 +39,30 @@ public class ObjectHelper_Tests
testClass.ChildClass.Name.ShouldBe("NewChildName");
}
[Fact]
public void TrySetPropertyWithValueType_SetsCorrectly()
{
// Arrange
var testClass = new MyClass();
const long newValue = 10;
// Act & Assert
ObjectHelper.TrySetProperty(testClass, x => x.Number, () => newValue);
testClass.Number.ShouldBe(newValue);
ObjectHelper.TrySetProperty(testClass, x => x.Number2, () => newValue);
testClass.Number2.ShouldBe(newValue);
ObjectHelper.TrySetProperty(testClass, x => x.Number3, () => newValue);
testClass.Number3.ShouldBe(newValue);
ObjectHelper.TrySetProperty(testClass, x => x.Number4, () => newValue);
testClass.Number4.ShouldBe(0); // readonly
ObjectHelper.TrySetProperty(testClass, x => x.Number5, () => newValue, ignoreAttributeTypes: typeof(IgnoreDataMemberAttribute));
testClass.Number5.ShouldNotBe(newValue); // ignore by attribute
}
class MyClass
{
public string Name { get; set; }
@ -52,6 +76,17 @@ public class ObjectHelper_Tests
[IgnoreDataMember]
public string Name5 { get; }
public long Number { get; set; }
public long Number2 { get; protected set; }
public long Number3 { get; private set; }
public long Number4 { get; }
[IgnoreDataMember]
public long Number5 { get; }
public MyChildClass ChildClass { get; set; }
public MyClass()

Loading…
Cancel
Save