5

几年前,曾经有过一场比赛,看谁能编写出最模糊的 C 代码,其中一些结果非常难以理解。C是这样的。你真的可以用预处理器搞砸事情。

然而,许多 C# 的新特性提供了一个绝佳的机会来混淆代码。我想知道是否有人对在代码的简洁和清晰之间找到正确的平衡有意见。让我举一个例子来讨论,将项目填充到ListView. (是的,我知道您可以通过数据绑定来做到这一点,但请跟我来。)

该控件是两列要填充的数组

struct Person
{
    public string name;
    public string address;
};

一种,清晰而简单的方法是这样的:

private void Fill(Person[] people)
{
    foreach(Person person in people)
    {
        string[] columns = new string[2];
        columns[0] = person.name;
        columns[1] = person.address;            
        ListViewItem item = new ListViewItem(columns);
        listView1.items.Add(item);
    }
}

清晰易懂。

我也可以这样写:

private void Fill(Person[] people)
{
    foreach(Person person in people)
    {
        string[] columns = new string[] { person.name, person.address };
        ListViewItem item = new ListViewItem(columns);
        listView1.items.Add(item);
    }
}

甚至:

private void Fill(Person[] people)
{
    foreach(var person in people) // Note use implicit typing here
    {
        listView1.items.Add(new ListViewItem(
        new string[] { person.name, person.address }));
    }
}

最后,我也可以这样写:

private void Fill(Person[] people)
{
    Array.ForEach(people, item =>
    listView1.items.Add(new ListViewItem(
    new string[] { person.name, person.address}));
}

每个人都或多或少地使用了该语言的各种新特性。您如何在简洁和清晰之间找到平衡?我们应该每年举办一次混淆 C# 比赛吗?

4

6 回答 6

26

你知道什么难吗?编写其他人可以阅读和维护的代码。任何白痴都可以编写可编译且无法维护的代码。

始终支持可维护性:这就是您找到平衡的方式。

编辑:

“任何傻瓜都可以编写计算机可以理解的代码。优秀的程序员编写人类可以理解的代码。”

  • Martin Fowler,重构:改进现有代码的设计

感谢roygbiv找到上述报价。向福勒道歉,因为他谋杀了他的报价;我知道我以前读过它,我只是不记得在哪里。

于 2010-01-23T21:52:16.107 回答
6

将所有内容塞入一行并不会使其“混淆”——它只会让您不必要地滚动很多东西。对于任何了解 C# 的人来说,理解您提供的任何示例仍然是微不足道的,而且如果您使用换行符,那么没有一个会比其他的更好或更差。

于 2010-01-23T21:58:08.997 回答
2

最大可读性的代码,但是

  1. 请记住,多余的冗长和句法噪音会损害可读性。如果更简洁的符号允许您更直接地表达您的意图,则更简洁可以同时提高可读性。例如,将真实的 lambda 函数与使用单方法接口模拟它们进行比较。

  2. 假设阅读您的代码的其他人是体面的程序员并且知道您正在使用的语言。不要假设语言律师的知识水平,而是假设具有良好的工作知识。不要以最小的公分母编写代码,因为虽然它可能使代码猴子更易于维护您的代码,但它会惹恼您和真正知道自己在做什么的维护程序员。

更具体地说,对于如此简单的事情,示例 1 有太多的语法噪音。示例 4 对人类来说非常难以解析。我想说 2 和 3 都很好,尽管在示例 3 的情况下我会重新格式化它,只是为了让人们更容易解析所有的函数调用嵌套:

private void Fill(Person[] people)
{
    foreach(var person in people)
    {
        listView1.items.Add(
            new ListViewItem(
                new string[] { person.name, person.address }
            )
         );
    }
}

现在您拥有两全其美的优势:它可以很容易地被人类解析,并且没有任何多余的、不必要的冗长临时变量。

编辑:我也认为使用隐式变量类型,即var大多数时候都很好。人们用动态语言编写完全可读的代码,其中隐式类型是唯一的类型,而且大多数时候,变量的形式类型是低级细节,与代码的高级意图几乎没有关系。

于 2010-01-24T00:40:50.657 回答
1

至少就您在此处提供的示例而言,我真的不认为混淆会随着您继续进行,直到您到达最后一个。即使在那里,任何模棱两可的唯一原因是 Lambda 的存在,这只是需要一些时间来适应。因此,新手可能会遇到最后一个问题,但不应该像旧的狂野 C 竞赛条目不可读那样发现其他不可读。

不同之处在于这些 C# 示例都处于相同的抽象级别 - 更简洁的示例只是删除“绒毛”。在 C 语言中,由于 A) 任意重命名/别名结构和 B) 将多个级别的内存访问捆绑到一个语句中,您有机会产生歧义。

总的来说,你可以用任何语言纠正晦涩难懂的代码,但我认为 C# 不像 C 那样容易出现这种情况,而且,事实上,我认为它是一种比许多语言更清晰的语言——即使使用一些更高级的语言结构体。

于 2010-01-23T21:55:33.403 回答
1

C# 和 VB.NET 语言的设计更加清晰,因为它们的操作级别比 C 更高。C 是可以说是接近金属的编程。编写像 C 一样的混淆 C# 是不可能的。

“任何傻瓜都可以编写计算机可以理解的代码。优秀的程序员编写人类可以理解的代码。”

  • Martin Fowler,重构:改进现有代码的设计
于 2010-01-23T22:32:56.523 回答
0

我没有发现这个例子被混淆了。

首先,意图非常清楚,新手更有可能了解 lambda 的功能,而不是不了解代码。这是使用更“高级”技术的理想场所——即使是不知道自己在做什么的人也能理解他们“应该”做什么。

其次,以上所有内容不仅没有被混淆,而且是完全惯用的 C#。最后一个可以说不是那么多,因为 Array.ForEach 的使用不那么广泛,大多数人(我曾与之合作过)都会使用 LINQ。

于 2012-11-28T12:56:37.893 回答