我有一个不可变的对象。例如下面的简单案例。
class Person {
public string Name {get;}
public int Age {get;}
public Person(string name, int age){
Name = name;
Age = age;
}
}
现在我希望有一个通用的扩展方法,例如
public static class ObjectExtensions {
public void T With<T,P>(this T target, Expression<Func<T,P>> selector, P value){
/* some implementatation */
}
}
这样我才能做到
var person = new Person("brad", 12).With(p=>p.Age,55);
person.Age.Should().Be(55);
With方法应使用反射来将构造函数参数名称与现有对象上的属性进行匹配。
目的是除了具有名称与属性匹配的参数的构造函数之外,不需要向不可变类添加额外的方法。
带有可为空参数的显式With方法,例如
class Person {
public string Name {get;}
public int Age {get;}
public Person(string name, int age){
Name = name;
Age = age;
}
public Person With(string? name, int? age){
return new Person(name ?? this.Name, age ?? this.Age);
}
}
虽然优雅不是我正在寻找我的用例的解决方案。
答案 0 :(得分:1)
这是一个例子。这可能会改进以缓存类型信息的速度,但它是您可以改进的基线。正如我在评论中提到的,这假设构造函数有一个名为与属性相同的参数,忽略大小写。它还假设只有一个构造函数,但您可以随意更新它。
public static T With<T, P>(this T target, Expression<Func<T, P>> selector, P value)
{
var expression = selector.Body as MemberExpression;
if (expression == null)
{
throw new InvalidOperationException();
}
var name = expression.Member.Name;
var constructor = typeof(T).GetConstructors().First();
var args = GetParamaters(target, value, constructor, name);
return (T)Activator.CreateInstance(typeof(T), args.ToArray());
}
private static IEnumerable<object> GetParamaters<T, P>(T target, P value, ConstructorInfo constructor, string name)
{
foreach (var parameterInfo in constructor.GetParameters())
{
if (parameterInfo.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase))
{
yield return value;
}
else
{
var property =
typeof(T).GetProperties()
.First(x => x.Name.Equals(parameterInfo.Name, StringComparison.InvariantCultureIgnoreCase));
yield return property.GetValue(target, null);
}
}
}