gpt4 book ai didi

c# - 在不可变对象(immutable对象)上创建一个 "with"方法

转载 作者:太空狗 更新时间:2023-10-29 20:36:25 25 4
gpt4 key购买 nike

我想在 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”方法?

最佳答案

这当然可以做到,并且是在包括 Entity Framework 在内的多个地方使用的方法。在 EF 中,它用于在查询中包含属性。

DbContext.Categories.Include(c=>c.Products)

对该集合的查询也会提取某个类别中的产品。您可以检查扩展方法中的表达式并像这样提取成员信息

((System.Linq.Expressions.MemberExpression)projection.Body).Member

当然在实践中你需要一些错误处理来确保表达式是一个成员表达式。然后你可以使用反射来设置适当的属性。您将需要一个 setter 才能工作,但您可以通过反射访问私有(private) setter,因此类型仍然可以有效地保持不变。这不是一个完美的解决方案,但我想它已经足够接近了。

我不知道有任何现有的此类方法的实现。我很想看看你的完整版本。

关于c# - 在不可变对象(immutable对象)上创建一个 "with"方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26982530/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com