【发布时间】:2014-11-17 21:43:02
【问题描述】:
我想模仿 C# 中的 F# 'with' 关键字(可用于记录)。
现在,当我创建一个新的不可变类时,我只需手动添加一些自定义“with”方法,如下所示:
public class MyClass
{
public readonly string Name;
public readonly string Description;
public MyClass(string name, string description)
{
this.Name = name;
this.Description = description;
}
// Custom with methods
public MyClass WithName(string name)
{
return new MyClass(name, this.Description);
}
public MyClass WithDescription(string description)
{
return new MyClass(this.Name, description);
}
}
对于我个人的 c# 开发,我尝试创建一个通用方法来执行此操作(在完美的世界中,我会使用 F#)。我做的“最好”是这样的:
public static class MyExtensions
{
public static TSource With<TSource, TField>(
this TSource obj,
string fieldName,
TField value)
where TSource : class
{
// Reflection stuff to use constructor with the new value
// (check parameters names and types)...
}
}
它可以工作,但我不太满意,因为我使用字符串参数丢失了编译时错误(现在我不关心性能问题)。
我真的很希望能够编写类似下面的代码,其中我将字符串参数替换为“投影”lambda:
var myClass1 = new MyClass("name", "desc");
var myClass2 = myClass1.With(obj => obj.Name, "newName");
我的扩展方法看起来像:
public static TSource With<TSource, TField>(
this TSource obj,
Expression<Func<TSource, TField>> projection,
TField value)
where TSource : class
{
// TODO
}
这是我的问题:
- 是否可以对投影结果使用反射并从中获取字段名称?
- 其他人是否已经在 C# 中完成了强大的“with”方法?
【问题讨论】:
-
我已经编辑了你的标题。请参阅“Should questions include “tags” in their titles?”,其中的共识是“不,他们不应该”。
-
第一个问题,请参阅stackoverflow.com/questions/671968/…。恐怕你的第二个并不是 StackOverflow 的主题。
-
你的
Expression仍然没有强制类型安全。有人仍然可以通过With(obj => "foo", "bar")之类的操作来调用它,而您没有真正的方法来处理它。 -
最好的办法是为这些不可变对象创建构建器对象。具有相同类型的可变版本,以及在两者之间来回移动的转换方法/运算符。然后,您可以获取一个对象,将其转换为构建器对象,设置一些值,然后将其转换回来。
标签: c# reflection lambda immutability