我可以将C# 9记录自动生成的方法中的敏感属性值隐藏吗?

12

我正在构建一个用户管理系统,使用一个域主机发送命令。这些命令是 record,既因为其具有init-only属性,也因为生成了帮助方法。然而,对于例如LoginUserCommand,我很快遇到了问题。

command.ToString()返回类似以下内容(添加了格式):

LoginUserCommand { 
    Identity = 10000000-1111-2222-3333-444444444444,
    CorrelationId = 20000000-1111-2222-3333-444444444444,
    Timestamp = 2013-07-26T16:45:20Z,
    IssuingUserId = 30000000-1111-2222-3333-444444444444,
    EntityId = a80c081c-cf91-4304-9baa-20fb20c8d9f7,
    IPAddress = 127.0.0.1,
    Password = ThisIsAPr0blem
}

显然,我可以通过覆盖在需要时重写ToString()的类上。天真地说,我可能会做一些像这样的事情:

public override string ToString()
{
    return base.ToString()
        .Replace(Password, "********");
}

但我在想是否忽略了一些内置的方法,可以让生成的 ToString() 方法屏蔽 Password 属性的值。


SecureString 可以作为一个选项吗? - Bill Tür stands with Ukraine
7
微软建议不要在任何情况下使用它。 - Matt Mills
1
@diemaus 将 override 替换为 virtual。只有当记录继承另一条记录时,才能使用 override。但是,如果您想防止编译器生成 PrintMembes,则可以将其提供为您想要的实现方式的 virtual - Youssef13
1
我还为此创建了一个源代码生成器。考虑一下查看一下。 https://github.com/Youssef1313/PrintMembersGenerator。你可以fork它并继续自己开发,发送PR或提出功能/错误问题,让我去解决。 - Youssef13
@Youssef13 - 接受的答案提到了你的项目,并附有链接。感谢你的工作!不幸的是,目前这还不是一个足够大的痛点,我不能优先贡献。 - Matt Mills
显示剩余2条评论
2个回答

17
你可以使用{{with}}语法重新映射记录,然后使用{{PrintMembers}}代替,我认为这样更加简洁:
public override string ToString()
{
    var builder = new StringBuilder();
    
    (this with { Password = null }).PrintMembers(builder);

    return builder.ToString();
}

也有提议引入一个类似于记录的[PrintMembersIgnore]属性,但是没有实现。不过可以通过代码生成来解决,这是dotnet团队建议的方法(见线程中的评论),已经开始了一个此项目


1
绝对更加简洁。最常调用 ToString() 方法的地方是在应用程序记录命令时。虽然这些命令是以调试模式进行记录的,但如果可以避免公开此信息,那么没有理由让其保留。 - Matt Mills
1
我尝试着在基础记录中玩弄并覆盖ToString,但是这种覆盖不会被超级记录(这个术语是否正确?)继承。 - mausworks
我添加了一些额外的信息,可能会引起兴趣。 - mausworks
为什么你在ToString()中使用StringBuilder而不直接使用以下内容? (this with { Password = null }).ToString(); - techExplorer
1
@techExplorer 因为这会导致无限递归调用(然后栈溢出)。 - riezebosch
1
@mausworks - 关于派生记录类型使用基类重写的 ToString():从 C# 10 开始,您可以在基类 ToString() 中添加 sealed,编译器将不再尝试在编译派生记录类型时添加自己的实现。参见 https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/record#built-in-formatting-for-display - Dave Werner

0
你可以在派生类中隔离敏感属性并重写PrintMembers
var s = new Entity("ss11", 99, "supersecret");
Console.WriteLine(s);
Console.WriteLine(s.secret);
// Output:
// EntityWithSecret { s1 = ss11, i2 = 99 }
// supersecret

public record EntityNoSecret(string s1, int i2);
public record Entity(string s1, int i2, string secret) : EntityNoSecret(s1, i2)
{
    protected override bool PrintMembers(StringBuilder builder)
        => base.PrintMembers(builder);
};

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接