给c#字典中的Key和Value命名,以提高代码的可读性

本文关键字:高代码 代码 可读性 命名 字典 Key Value | 更新日期: 2023-09-27 17:50:54

在c#结构体中,我们可以通过变量名清楚地知道它的用途。例如,

public struct Book
{
    public string title;
    public string author;
}

那么,我知道b.title是一个字符串类型,它引用的是title。

但是在c#字典中,我们只能指定类型
Dictionary<string,string> d

我怎样才能使代码更可读,这样字典的键是字符串类型,它是指标题,值是字符串类型,它是指作者?这意味着,其他人可以很容易地知道d["J.R.R.在阅读代码时错误地使用了字典。

编辑@mike z建议使用变量名titleToAuthor来提高可读性。但我真正的问题是,在代码中有嵌套的字典。例如

Dictionary<string, Dictionary<string, string>>, 
or even 3 levels   
Dictionary<string, Dictionary<string , Dictionary< string , string[] >>>. 

我们想保持使用字典的便利性,而不创建我们自己的类,但同时我们需要一些方法来提高可读性

给c#字典中的Key和Value命名,以提高代码的可读性

根据@ScottDorman的建议,你可以定义一个新的类型TitleAuthorDictionary,衍生自Dictionary<string, string>,像这样:

public class TitleAuthorDictionary : Dictionary<string, string>
{
    public new void Add(string title, string author)
    {
        base.Add(title, author);
    }
    public new string this[string title]
    {
        get { return base[title]; }
        set { base[title] = value; }
    }
}

然后可以使用可读性更强的Dictionary Collection,如下所示:

TitleAuthorDictionary dictionary = new TitleAuthorDictionary();
dictionary.Add("Title1", "Author1");
dictionary.Add(title: "Title2", author: "Author2");
dictionary["Title2"] = "Author3";

在。net 6和c# 10中,你现在可以使用global using指令在你的项目中提供类型别名。

将内置类型的别名放在一个地方,例如GlobalUsings.cs

global using Title = System.String;
global using Author = System.String;

然后在你的字典中使用别名以获得更好的可读性。

Dictionary<string, Dictionary<Title, Author>>

如果不与语言抗争就无法解决的问题,我建议通过文档解决。标识符作为自我文档的一种形式包含在该类别中。

所以要在这种类型中添加自我文档:

using TitleToAuthor = System.Collections.Generic.Dictionary<
    string, // title
    string  // author
>;

为该类型的实例添加自文档:

TitleToAuthor title_to_author = new TitleToAuthor();

不幸的是,你不能嵌套using指令作为泛型类型参数,所以使用这样的解决方案会让你在文件顶部的using指令非常难看,但至少那些难看的代码,写一次,就会在它的左边创建一个非常可读的别名(显示它的确切用途),你可以在其余代码中引用它,而不必实际创建新的数据类型。

另一种方法是简单地创建新的数据类型,从Dictionary继承,例如,如果你有更多的新类型可以做,而不是简单地获得一个更可读的类型名称,我建议这条路线,比如添加对该集合特别有用的方法,或者如果该集合在许多源文件中使用(从那时起,你必须重复相同的使用指令很多)。

在这种情况下,组合可能比继承(将字典存储为成员)更好,因为这样您就可以根据需要创建更小的子集接口(并且可能通过仅提供对特定容器类型完全有意义的高级函数来减少滥用它的方法),而不仅仅是一个完整的字典接口+更多的方法。在这种情况下,您将把这个有点难以阅读的泛型通用字典转换为一个隐藏的实现细节,该实现细节不仅在类型名称方面读起来更好,而且还提供了一个更小、更定制(不那么通用)的接口,可以更具体地处理您的需求。对于一个简单的例子,允许为键或值指定空字符串可能是错误的。字典不会强加这样的断言,但是您自己设计的接口可以使用字典作为私有实现细节。

如果您对字典的键/值参数的可读性感到困惑,那么问题可能并不在于字典的可读性,而在于特定字典的公开暴露量。如果您有一个字典实例,甚至是具有非常公开可见性的类型,并且到处都被引用,那么您可能不仅要关心这些代码的可读性,还要考虑允许访问它的人做任何他们想做的事情,而这在一个完整的字典中是允许的(包括您可能不希望在更大范围内发生的事情)。毕竟,即使是像float这样的类型也很少告诉你它应该做什么,但是我们倾向于这样写代码:float要么是类/函数的实现细节,要么只是函数参数/返回类型,它们的功能相当明显。因此,也许最好设法使这样的字典不那么可见,而更多地隐藏在私有的实现细节中,因为实现细节的清晰度和可读性通常不如将在整个代码库中访问的接口中更公开可见的部分那么重要。

按照设计,字典是一个键值对,公开的集合也是这样调用的。如果需要更显式的东西,可以派生自己的自定义字典或在自己的类上实现适当的字典接口。您还可以考虑将其实现为键集合,其中提供lambda表达式以从数据派生键。