C#(csharp)这门语言的优势在哪?

身边同学朋友一问,居然都说是为了Unity3d才来学的C#。难道这门语言自己没有其他“作用”了嘛?
关注者
748
被浏览
1,663,637

119 个回答

语法符合大多数人的直觉(Anders的品味还是很高的),诸多语法糖不只是糖,是实实在在经过严密设计的语言功能,而不像一些JVM平台的语言受限于JVM无法实现诸如Span这些功能。

性能强,有些时候可以达到甚至超过编译性语言的性能。

Which programming language is fastest? | Computer Language Benchmarks Game

结果: rwing.github.io/debian-

在该测试的合计成绩中,C#的耗时小于Java和go, 仅次于c/c++/rust 3大native语言

当然有人会质疑该测试中实现算法的代码没有优化,那么可以比较一下实际的项目

Ryujinx是一个C# .NET 5编写的Switch模拟器。Switch从性能看是本世代(第九世代)的掌机,用着一颗过时且廉价的Tegra X1, 4核ARM A57 CPU加上256 CUDA的Maxwell GPU.

虽然性能不高(相较于zen2+RDNA2的隔壁两家,switch的性能只能称得上是掌机),但是想在PC上运行HLE模拟器,那么就得把ARM指令集(包括v7a和v8a)即时编译到本机指令集,把NVN api翻译到OpenGL, 再模拟Horizon OS微内核操作系统各个系统服务,从这一点来看,模拟其所需的CPU性能大约至少要5-10倍于Tegra X1 CPU的性能

Ryujinx用C# .NET 5实现了以上所有功能(包括一个全功能的使用C#编写的ARM to x86 即时编译器),并且性能不差于使用c++的yuzu 。例如,在一台甚至无法高特性流畅运行2077的机器也可以4K 60fps运行近日发布一款7分作品,而该作品在switch上仅能以720p/900p 30fps运行: 运行截图

模拟器可不像Unity里的mono一样只跑游戏逻辑,Ryujinx的存在表明.NET 5的运行时性能已经和c/c++/rust这些几乎没有运行时且经过gcc/llvm优化的native语言相当。

答过类似的问题。

很多游戏开发者都是由于Unity而“被迫”使用C#的。但用过一段时间,就会由衷赞叹: 真香

如果有些同学没感觉到很香,有可能是没有仔细和其它语言比较 :)

1、从世界范围看,C#已经是一门广泛流行的语言

所谓的“流行语言TOP10”有好几种,但无论参考TIOBE还是Github,流行语言的前五位的竞争者,基本都是 Java,Python,C,C++,C#,Visual Basic, JavaScript 。不同的榜单排名有差异,但你总能在前几位看到它们。而且从十年前开始,C#的地位一直在稳步上升。

由于阿里云计算以及相关技术栈的流行,在国内Java是当之无愧的老大。但由于游戏领域大量使用Unity和C#,所以如果汇总国内招聘网站的关键词,C#出镜率依然能排进前5(前五位:Java,C++,C#,JavaScript,Python)。参考链接: 2019年10月中国编程语言排行榜_毛毛虫-CSDN博客

可以预见,随着技术栈的迭代,C#的地位会越来越稳固。但除非有颠覆式的变革,在通用开发领域Java依然占领导地位。

2、C#良好兼容了值类型/引用类型,在发展中逐步解决了其他高级语言没解决好的问题

说完了C#整体的情况,下面说的都是C#在语言设计上的一些亮点。

纵观主流语言,C语言在语法上是以值类型为基础,借助指针实现引用类型;而Python/Lua等语言,是以引用类型为基础。

论性能和细节控制力,C语言的设计上限更高;但是论简易程度,Python更为统一、易用。这一基本矛盾在之前的语言里都没有解决好。

而C#很好的总结了前人的经验,在基础语法上就区分了值类型和引用类型。对初次接触编程的同学来说这一点容易造成学习障碍,但是只要掌握了它,就会给实际工作带来极大便利。

反观历史,C#也曾经因为 值类型/引用类型 保守诟病,“拆箱”和“装箱”一直是个招黑的设计。但后来我们看到,随着泛型的成熟、随着泛型容器代替object容器,装箱和拆箱的问题已经在很大程度上解决了。

还有对异步的支持等等,C#的设计最初带来了一些问题,但现在的C#已经加入了基于多线程的异步语法,比如async和await等,基本让人满意。

3、充分利用栈空间,非常高效,做了一部分C/C++擅长的事

值类型有一大特点,就是能充分利用栈空间。高级语言的GC特性一直饱受诟病,但下面的Unity常见代码,运行时没有GC:

// 通过输入的三维向量,移动物体的位置
void Move(Vector3 input)
    // 演示代码,有意分成很多行
    input = input.normalized;
    Vector3 move = input * 2.0f;
    move *= Time.deltaTime.
    transform.position += move; 

这段代码没有在堆上分配空间,你所看到的操作全都是在栈上进行的,GC压力为0。我认为这是C#最令人惊艳的一点。

一般来说数组长度较长,默认分配在堆上。但是C#也提供了便利的语法,在栈上分配数组,对项目后期优化来说简直是神技:

public void unsafe foo()
    int* bar = stackalloc int [10];

没错,C#依然保留了指针,但一般仅用于局部的unsafe代码。在局部热点可以完全解放性能。

4、良好的语法设计和库函数设计,引导程序员写出更快且更自然的代码

C#中最常用的容器List,也具有一些良好的设计(当然其它语言也有类似的优点)

        // 新建一个list,长度为0。但在堆中预留10万个位置
        List<int> list = new List<int>(100000);
        // 加入很多元素,由于容量足够没有GC
        for (int i=0; i<89000; i++)
            list.Add(i);
        // 用过以后清空list,长度变成0
        list.Clear();
        // 但容量还是10万,继续增加元素还是没有GC
        for (int i = 0; i < 99000; i++)
            list.Add(i);