混淆的C#代码-简洁和清晰之间有什么平衡?

问题描述 投票:5回答:6

几年前曾经有一个竞赛,看谁可以产生最混淆的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#竞赛吗?

readability
6个回答
25
投票

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

Always倾向于可维护性:这就是找到平衡的方式。

编辑:

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

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

感谢roygbiv查找以上引用。对福勒谋杀他的名言表示歉意;我知道我以前读过它,只是不记得在哪里。


6
投票

将所有内容填充到一行中不会使其变得“模糊”-只会使您不必要地滚动很多。对于任何一个了解C#的人来说,理解您所介绍的任何示例仍然是微不足道的,并且如果您使用换行符,那么任何一个都不比其他示例更好或更糟。


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在大多​​数情况下都可以。人们用动态语言编写完全可读的代码,其中隐式类型是唯一的一种类型,并且在大多数情况下,变量的形式类型是低级的细节,与代码的高级意图几乎没有关系。


1
投票

至少关于您在此处提供的示例,我真的不认为混淆会随着您的前进而上升,直到您到达最后一个。即使在那儿,任何歧义的唯一原因是Lambda的存在,这只是需要一些习惯。因此,新手可能在最后一个上遇到麻烦,但不应以旧的野生C竞赛条目不可读的方式发现其他人不可读。

不同之处在于,这些C#示例都处于相同的抽象级别-更加简洁的示例只是消除了“绒毛”。在C语言中,由于A)任意重命名/别名化的构造,以及B)捆绑到一个语句中的多个级别的内存访问,因此您可能会产生歧义。

整体来说,您可以纠正任何语言中的晦涩代码,但我不认为C#像C一样容易出现这种情况,实际上,我认为它是一种比许多语言更清晰的语言-即使使用某些更高级的构造。


1
投票

C#和VB.NET语言的设计出于清晰度方面的考虑,因为它们的运行级别比C.高。C的编程是如此紧密。在设计上不可能像C那样编写模糊的C#。


0
投票

我没有发现混淆的示例。

© www.soinside.com 2019 - 2024. All rights reserved.