C#记录,有没有办法将属性Name作为记录的一部分,以便我可以与表达式一起使用?

问题描述 投票:0回答:1

我正在编写一个类似于 Fluent Validator 的库,它将允许对象修改。对于普通类,它工作没有问题,但我尝试用记录编写类似的方法,并偶然发现了一个大问题。

规则的定义与 Fluent Validator 中的相同:

RuleFor(x => x.Name).ForceUppercaseFormat();

方法

ForceUppercaseFormat()
在扩展类中定义,如下所示:

public static ImmutableLogicRuleBuilder<TModel,string> ForceUppercaseFormat<TModel>(this ImmutableLogicRuleBuilder<TModel,string> builder)
    where TModel : INamed
{
    builder.Apply(new StringToUpperCase(), (model, changedName) =>
    {
        model = model with { Name = changedName };
        return model;
    });

    return builder;
}

供参考

public interface INamed
{
    string Name { get; }
}

有两个问题。一是

Name
没有
init
。我一开始没有添加它,因为我会为类和记录重用这个接口。我决定将重点放在记录上,所以我添加了
init
。这并没有解决任何问题。根据 Rider 的说法,
TModel
不是有效记录,因此我无法使用
with
运算符。

有没有办法限制通用仅适用于记录?

作为一种解决方法,我可以为

ForceUppercaseFormat()
格式添加两个重载,其中
Action<TModel, TProp>
Func<TModel, TProp, TModel>
作为类和记录的变体,但这看起来不太好,而且需要很多额外的代码。

// for class
RuleFor(x => x.Name).ForceUppercaseFormat((x, newName) => x.Name = newName);

// for records
RuleFor(x => x.Name).ForceUppercaseFormat((x, newName) => x with {Name = newName});
c# generics record
1个回答
0
投票

with
表达式可以与记录类、匿名类型或值类型一起使用。

不存在需要记录类或匿名类型的“通用约束”。在泛型方法中使用 with 的唯一方法是将类型限制为

struct
(即使如此,ReSharper 也曾
遇到过这样的问题,所以我只能假设 Rider 也是如此。) 可能最简单的选择是定义所有模型都必须实现的突变接口 - 例如:

public interface INamed { string Name { get; } } public interface INamed<TModel> : INamed where TModel : INamed<TModel> { TModel WithName(string nameName); } public record Foo(string Name) : INamed<Foo> { public Foo WithName(string nameName) => this with { Name = newName }; }

然后您可以将此约束添加到您的方法中:

public static ImmutableLogicRuleBuilder<TModel,string> ForceUppercaseFormat<TModel>( this ImmutableLogicRuleBuilder<TModel,string> builder) where TModel : INamed<TModel> { builder.Apply(new StringToUpperCase(), (model, changedName) => { model = model.WithName(changedName); return model; }); return builder; }

	
最新问题
© www.soinside.com 2019 - 2025. All rights reserved.