V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
w568w
V2EX  ›  C#

C# 有哪些显著的缺点?

  •  1
     
  •   w568w · 12 天前 · 2084 次点击

    之前久仰 C# 大名,但一直没实际接触过,一是感觉微软的东西都不靠谱,二是觉得这语言只有游戏产业和 ASP.NET 服务器在用,三是不知道从哪里留下了「 C# 运行性能特别差」的印象。

    今天在 Windows 上写了个小数据处理脚本,出于好奇去安装了一下 .NET 9 ,用 GPT 把 Python 转成了 C# 去跑,发现这东西跑起来飞快,比 Python 快了不止七八倍,CPU 也吃满了。

    继而去查了一下 Debian 的 The Computer Language Benchmarks Game 。不看不知道,好家伙,现在 C# aot 都能在 CLBG 排到 Go 头上去了:

    Language elapsed secs / fastest
    Intel C 1.1
    C 1.3
    C# aot 1.5
    Java 1.5
    Go 1.6

    虽然性能测试和 Java 差不多,但内存占用要少 50%~70%。试了一下 AOT 编译,编译出来就一个 4~5MB 可执行文件,体积很小也无依赖,额外开销基本和 Rust 、C++ 那些原生语言差不多无感。

    但这可是带 GC 的「重型」语言啊,微软这几年的优化确实厉害。

    所以感觉这语言挺有意思,准备最近多花时间当兴趣学习一下,但还是对微软的东西不是很放心。问问各位 C# 开发:C# 有什么特别明显缺点或者写起来卡手的地方吗? 提前谢谢大家。

    39 条回复    2025-01-16 00:27:02 +08:00
    gpt5
        1
    gpt5  
       12 天前 via iPhone   ❤️ 1
    容易念不对名字
    neteroster
        2
    neteroster  
       12 天前 via Android   ❤️ 1
    语言感觉挺好的。我来提一个显著的:官方调试器 vsdbg 是专有的,所以如果你用除 vs 和 vscode 等之外的部分编辑器的话(例如 cursor )就会有调试方面的问题,只能用一些平替调试器
    z1829909
        3
    z1829909  
       12 天前
    基本是个语言都会比 python 快, GIL 锁导致 python 单进程顶天了跑一个核.
    w568w
        4
    w568w  
    OP
       12 天前
    @gpt5 C Sharp 太拗口了,我还是喜欢念 C 、C 艹、C 井,哈哈


    @neteroster 用 Jetbrains 的 Rider 是不是就没有这个问题了?


    @z1829909 确实,不过我看翻译出来的 C# 代码也没用多线程(至少明面上没用),可能还是 Python 的 JSON 解析和数组处理效率太低了。
    maigebaoer
        5
    maigebaoer  
       12 天前 via Android   ❤️ 1
    缺点就是互联网公司用的少
    geelaw
        6
    geelaw  
       12 天前 via iPhone   ❤️ 2
    有一些很坏的特性,比如数组逆变(性能有极大损失),类型兼容性版本太多并且不一致(比如装箱 int 不可以拆箱为 uint ,但装箱的 int enum 可以拆箱为 int ,但 int[] 是 uint[],并且我永远记不住 int[] 是不是 int enum 数组;完全采用依名判定会简单很多),再比如实现多个可变接口时可变接口解析的歧义性,当然这都是 CLR 的问题。

    C# 自己的问题大概是加入一些不必要的限制,比如古代的 C# 语言不许用 Enum 作为范型约束,虽然它完全有意义并且自古以来就受到 CLR 的支持。
    geelaw
        7
    geelaw  
       12 天前 via iPhone
    @geelaw #6 “数组逆变”应该更正为“数组协变”。
    smilenceX
        8
    smilenceX  
       12 天前   ❤️ 1
    @w568w #4 , 我不确定 Rider 是不是用的官方调试器,但在开发过程中,调试完全没问题。
    klo424
        9
    klo424  
       12 天前
    一直用 C#,很顺滑,缺点就是换个语言就觉得很难用。
    HairShort
        11
    HairShort  
       12 天前 via Android
    函数名是大驼峰,javaer 各种别扭
    pigf
        12
    pigf  
       12 天前
    @HairShort 还有换行
    glcolof
        13
    glcolof  
       12 天前   ❤️ 1
    C#有一个所有语言都有的通病:缺乏优秀的、使用广泛的跨平台 UI 框架。
    wanguorui123
        14
    wanguorui123  
       12 天前
    相对 JAVA/GO 工资不高
    niubee1
        15
    niubee1  
       12 天前   ❤️ 1
    你在发微博发推发知乎的时候容易发出莫名的话题
    june4
        16
    june4  
       12 天前
    珍爱生命,远离 .net
    dwu8555
        17
    dwu8555  
       12 天前
    C#语言挺好的,Linq 相当牛逼。

    但是感觉还是没有 Golang 用着有感觉
    ShinichiYao
        18
    ShinichiYao  
       12 天前
    C#其实就是 VB
    Skifary
        19
    Skifary  
       12 天前
    缺点:是微软开发的
    优点:是微软开发的🐶
    DTCPSS
        20
    DTCPSS  
       12 天前   ❤️ 1
    C# 设计者之一 Eric Lippert 总结的 C# 十大设计缺陷,基本看这一篇就够了:
    https://www.informit.com/articles/article.aspx?p=2425867
    HFX3389
        21
    HFX3389  
       12 天前
    > 试了一下 AOT 编译,编译出来就一个 4~5MB 可执行文件,体积很小也无依赖

    那这个编译出来的可执行文件能够在没有安装运行环境.NET 9 下运行吗
    gadfly3173
        22
    gadfly3173  
       12 天前 via Android   ❤️ 1
    linux 上的缺点:C#的 FileSystemWatcher 只支持每个实例侦听一个目录,并且每侦听一个目录就需要创建一个 inotify 实例,而一般 linux 的 inotify 实例上限一般是 128 。如果你要用 C#做一个需要监听多个目录变化的程序,那么很容易达到这个上限,导致系统上无法再创建任何 inotify 实例。这个问题看起来 node.js 和 java 都是没有的。😓

    dotnet/runtime#62869
    chenqh
        23
    chenqh  
       12 天前
    @z1829909 python 没有 JIT 啊,一个核都算了,反正 web 小项目可以把进程当线程用.
    gadfly3173
        24
    gadfly3173  
       12 天前 via Android
    @HFX3389 可以的,publish 的时候指定--self-contained 就行。一个使用.net9 aot 编译的例子就是 sourcegit-scm/sourcegit
    csys
        25
    csys  
       12 天前   ❤️ 1
    最致命的问题是生态,尤其是在国内

    其它的问题比如函数染色是许多其它编程语言也有的,但是生态完全是独一份的致命伤,而且越来越致命

    另一个隐藏的问题是微软,微软给 C#/.NET 提供了持续的高质量的支持,但是又不断地扼杀 C#/.NET 社区
    Akiya
        26
    Akiya  
       12 天前
    缺点就是你用了 C#之后再用别的语言就用的没那么舒服了
    Bronya
        27
    Bronya  
       11 天前   ❤️ 1
    我自己写程序经常用 C#,手上还有个用 blazor 写的面板工具,一些脚本处理也都是用 dotnet-script 方便一键运行,需要图形界面的话就用 WPF 搞。
    目前为止遇到的问题有(包括语言及生态):

    * AOT 不支持交叉编译
    * self contained 模式下部分库对修剪功能支持不到位,导致想写个程序给没有安装 run time 的机器上运行时,必须打包整个运行时,会使打包文件过大(几行代码打包下载近百兆,修剪了又会报错。)。
    * rider 对 blazor 热重载支持不如 vs ,经常需要重启。而 vs 又经常无法识别代码,经常没有问题的代码会报错,关闭重新打开就又好了( vs 2022 )。
    * 经常会纠结到底用不用可空类型。
    * 有些东西如果不按照官方的推荐搞,会变得很麻烦。比如 blazor 中的认证,如果不用官方的 Idendity 包,会很麻烦,但是官方包里东西又太多了,我仅仅想要个用户名密码验证而已。
    * 异步函数传染问题(这点真没 go 方便)
    * 没有好的方式写安卓应用( MAUI 问题太多了)
    ZGame
        28
    ZGame  
       11 天前
    相比较 java 来说,优点是写起来太顺畅了。 缺点是没有布道师,和相应的广泛的开源生态和 copy 代码。
    z1829909
        29
    z1829909  
       11 天前 via Android
    @chenqh 一般 python 的 web 项目不也是起多个进程,每个进程里走异步 io ,如果纯单进程 cpu 满了,会影响他调度造成超时。
    w568w
        30
    w568w  
    OP
       11 天前
    @geelaw 感谢。关于数组协变,我的想法是不是 C# 根本不应该支持在数组上自动协变?下面也有朋友提到协变后的数组写入其他类型的元素是运行时错误,极难检查。

    @niubee1 @ShinichiYao 此话怎讲?

    @DTCPSS 看了一下,很有收获,确实把语言中最肮脏的设计都列出来了。(好在 Java 等 GC 语言也共享了几个,比如无 Destructor 。)

    @gadfly3173 看起来也没有那么难修复,感觉是微软特有的 Windows 中心思维在作祟。不知道 Mono 有没有同样的问题?

    @csys @ZGame C# 的生态非常差吗?我看 NuGet 上的库挺多的(虽然基本都是围绕 Windows 转)。

    @Bronya 感谢。「异步函数传染」这点,其实我写 Rust 、Python 、Dart 、Kotlin…… 早就习惯了,所有函数全部染色就好了,现在写 Go 好像也没什么感觉了。「 Self-contained 修剪不到位」这个确实是有点硬伤,我得多写程序测试测试。
    geelaw
        31
    geelaw  
       11 天前 via iPhone
    @w568w #30 数组可变性是从 JVM 抄到 CLR 里最恶心的特性之一,根本不应该支持。解决方法是 public readonly struct S<T> where T : class { public readonly T O; public S(T o) { O = o; } } 然后用 S<T>[]。
    Jlzeng
        32
    Jlzeng  
       11 天前
    aot 和很多现代特性不兼容(反射、emit 、动态加载 dll )没法既要又要。
    chenqh
        33
    chenqh  
       11 天前
    @z1829909 但是单进程 cpu 满了,这种好查啊
    yuandong
        34
    yuandong  
       10 天前
    国内大公司用的少,优秀的 C#程序员也少
    hez2010
        35
    hez2010  
       6 天前
    @geelaw 其实 int 和 enum 的类型转换那块儿是对 C++ 行为的兼容,类似的还有 0 可以不需要转换就能赋值给任何的 enum 。
    geelaw
        36
    geelaw  
       6 天前
    @hez2010 #35 我说的是装箱拆箱的问题,不是 int 和 enum 存在转换的问题。

    StringSpiltOptions e = (StringSplitOptions)1;
    int i = (int)e;

    不是

    object o = (StringSplitOptions)1;
    int i1 = (int)o; // bad, but works
    int i2 = (int)(StringSplitOptions)o; // good, and works

    装箱拆箱在 C++ 标准里最接近的是 std::any_cast ,它并不允许把存放了 enum 的 any 通过 any_cast 变成 int ,但这个论证无意义,因为 C++ 的 any 比 CLR 晚了很久。

    另一个接近的是 C++ 允许 std-layout type 的 pointer 和它 first member 的 pointer 做 reinterpret_cast ,但是 C# 里面装箱后的值类型(根据 CLR 定义,这是和值类型不同的、一个自动产生的类型)应该理解为多态类型(“具有虚表”),此时不是 std-layout ,所以也不适用这个类比。
    sagaxu
        37
    sagaxu  
       5 天前   ❤️ 1
    最大的缺点是生态差,

    比如这个会导致异步 IO 被阻塞的 mysql connector 的 bug ,2013 年提出,2023 年才修复
    https://bugs.mysql.com/bug.php?id=70111

    比如微信支付 SDK ,2024 年了还不提供.net
    https://pay.weixin.qq.com/doc/v3/merchant/4012076498
    hez2010
        38
    hez2010  
       5 天前   ❤️ 1
    @sagaxu 微软支付不提供 .net 版 sdk 并不妨碍第三方提供完整的 sdk: https://github.com/fudiwei/DotNetCore.SKIT.FlurlHttpClient.Wechat

    至于 mysql connector ,感觉用 .net 的更多还是用 pgsql ,而不是 mysql
    nebkad
        39
    nebkad  
       2 天前   ❤️ 1
    ref struct, struct, record struct, readonly struct.....
    过于甜了,最近几年加的语法糖太多显得很乱,功能不是很正交,类型系统瑕疵很多,譬如楼上 GeeLaw 提及的
    现在好像 ref struct 还不能实现 interface ( C# 13 据说可以了?)然而对于高性能 IO 来说 ref struct 又很重要
    但是 LINQ 真的值得吹爆,至今找不到竞品
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2648 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 05:03 · PVG 13:03 · LAX 21:03 · JFK 00:03
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.