mirror of https://github.com/abpframework/abp.git
15 changed files with 184 additions and 69 deletions
@ -0,0 +1,57 @@ |
|||
using System; |
|||
using System.Collections.Concurrent; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Linq.Expressions; |
|||
using System.Reflection; |
|||
|
|||
namespace Volo.Abp |
|||
{ |
|||
public static class ObjectHelper |
|||
{ |
|||
private static readonly ConcurrentDictionary<string, PropertyInfo> CachedObjectProperties = |
|||
new ConcurrentDictionary<string, PropertyInfo>(); |
|||
|
|||
public static void TrySetProperty<TObject, TValue>( |
|||
TObject obj, |
|||
Expression<Func<TObject, TValue>> propertySelector, |
|||
Func<TValue> valueFactory, |
|||
params Type[] ignoreAttributeTypes) |
|||
{ |
|||
TrySetProperty(obj, propertySelector, x => valueFactory(), ignoreAttributeTypes); |
|||
} |
|||
|
|||
public static void TrySetProperty<TObject, TValue>( |
|||
TObject obj, |
|||
Expression<Func<TObject, TValue>> propertySelector, |
|||
Func<TObject, TValue> valueFactory, |
|||
params Type[] ignoreAttributeTypes) |
|||
{ |
|||
var property = CachedObjectProperties.GetOrAdd( |
|||
$"{obj.GetType().FullName}-{propertySelector}{(ignoreAttributeTypes != null ? string.Join("-", ignoreAttributeTypes.Select(x => x.FullName)) : "")}", () => |
|||
{ |
|||
if (propertySelector.Body.NodeType != ExpressionType.MemberAccess) |
|||
{ |
|||
return null; |
|||
} |
|||
|
|||
var memberExpression = propertySelector.Body.As<MemberExpression>(); |
|||
|
|||
var propertyInfo = obj.GetType().GetProperties().FirstOrDefault(x => x.Name == memberExpression.Member.Name && x.DeclaringType == obj.GetType()); |
|||
if (propertyInfo == null || propertyInfo.GetSetMethod(true) == null) |
|||
{ |
|||
return null; |
|||
} |
|||
|
|||
if (ignoreAttributeTypes != null && ignoreAttributeTypes.Any(ignoreAttribute => propertyInfo.IsDefined(ignoreAttribute, true))) |
|||
{ |
|||
return null; |
|||
} |
|||
|
|||
return propertyInfo; |
|||
}); |
|||
|
|||
property?.SetValue(obj, valueFactory(obj)); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,78 @@ |
|||
using System.Runtime.Serialization; |
|||
using Shouldly; |
|||
using Xunit; |
|||
|
|||
namespace Volo.Abp |
|||
{ |
|||
public class ObjectHelper_Tests |
|||
{ |
|||
[Fact] |
|||
public void TrySetProperty_Test() |
|||
{ |
|||
var testClass = new MyClass(); |
|||
|
|||
ObjectHelper.TrySetProperty(testClass, x => x.Name, () => "NewName"); |
|||
testClass.Name.ShouldBe("NewName"); |
|||
|
|||
ObjectHelper.TrySetProperty(testClass, x => x.Name2, () => "NewName2"); |
|||
testClass.Name2.ShouldBe("NewName2"); |
|||
|
|||
ObjectHelper.TrySetProperty(testClass, x => x.Name3, () => "NewName3"); |
|||
testClass.Name3.ShouldBe("NewName3"); |
|||
|
|||
ObjectHelper.TrySetProperty(testClass, x => x.Name4, () => "NewName4"); |
|||
testClass.Name4.ShouldBe("Name4"); // readonly
|
|||
|
|||
ObjectHelper.TrySetProperty(testClass, x => x.Name5, () => "NewName5", ignoreAttributeTypes: typeof(IgnoreDataMemberAttribute)); |
|||
testClass.Name5.ShouldNotBe("NewName5"); // ignore by attribute
|
|||
|
|||
ObjectHelper.TrySetProperty(testClass, x => x.ChildClass.Name, () => "NewChildName"); |
|||
testClass.ChildClass.Name.ShouldNotBe("NewChildName"); |
|||
|
|||
ObjectHelper.TrySetProperty(testClass.ChildClass, x => x.Name, () => "NewChildName"); |
|||
testClass.ChildClass.Name.ShouldBe("NewChildName"); |
|||
|
|||
ObjectHelper.TrySetProperty(testClass.ChildClass, x => x, () => new MyChildClass |
|||
{ |
|||
Name = "NewChildName" |
|||
}); |
|||
testClass.ChildClass.Name.ShouldBe("NewChildName"); |
|||
} |
|||
|
|||
class MyClass |
|||
{ |
|||
public string Name { get; set; } |
|||
|
|||
public string Name2 { get; protected set; } |
|||
|
|||
public string Name3 { get; private set; } |
|||
|
|||
public string Name4 { get; } |
|||
|
|||
[IgnoreDataMember] |
|||
public string Name5 { get; } |
|||
|
|||
public MyChildClass ChildClass { get; set; } |
|||
|
|||
public MyClass() |
|||
{ |
|||
Name = "Name"; |
|||
Name2 = "Name2"; |
|||
Name3 = "Name3"; |
|||
Name4 = "Name4"; |
|||
Name5 = "Name5"; |
|||
ChildClass = new MyChildClass(); |
|||
} |
|||
} |
|||
|
|||
class MyChildClass |
|||
{ |
|||
public string Name { get; set; } |
|||
|
|||
public MyChildClass() |
|||
{ |
|||
Name = "Name"; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue