百因必有果:C# 程序在各个平台的兼容性观察

事情就像这篇文章里说的一样:dotnet core 吸引了人们的眼球 (“我写的 WPF app 能通过 .NET Core 能跨平台了?1 2 ”),但人们不知道自己从哪里来,更不知道自己该向哪里去。

因此,让我们退后一步,评估刚刚发生的事情,因为炒作让你兴奋,即使现实不是那么有趣:

    我们从 .NET、Windows 窗体和 WPF 开始,在大多数版本上工作。
    我们打开源的 .NET 并创建了没有 GUI 的 .NET core 。
    现在,我们将 Windows Forms 和 WPF 添加到 .NET core,但仅在 Windows 上。
    现在我们有 .NET(core)版的 Windows Forms 和 WPF ,可以在 Windows 10 上运行了。
    大进步!(.NET core 开发人员自封的。)

(嗯,为所谓跨平台的 .NET core 添加了一些 Windows-only 的 feature 并继续声称自己是跨平台的 —— 果然大进步!大骗子又进步了,越来越会骗人了 )

结果就是:很多这样的话会出现:

  1. Dotnet core 是跨平台的
  2. Dotnet core 又有大新闻啦,支持了 xxxxx
  3. Dotnet core 只支持 xxxxx 在 Windows 上运行,方便 Windows 软件能够从 .NET Framework port 到 Dotnet core
  4. Dotnet core 是 跨平台

  1. Dotnet core 又有大新闻啦,支持了 xxxxx (最近刚支持了 WPF )
  2. Dotnet core 只支持 xxxxx 在 Windows 上运行。不好意思 linux 用户们 又让你们空欢喜啦 (不如去用 mono)
  3. Dotnet core 是 跨平台

嗯,“跨平台” 但是在各个平台上的表现并不一致,这很 MS 。

难怪它会招致这样的评价:
如果没有跨平台 GUI,.NET Core 与非 Windows 程序员基本上无关。 —— 无论它怎么吹自己跨平台,.NET Core 在 Win, Linux, Mac 三个平台的表现是一致(就像 Java 在三个平台的表现是一致的)的吗? NO

从一个迁移工程师的角度,migration 是一件需要了解方方面面的事情:从系统平台,到 SDK 的版本,这其间的诸多拦路虎,都可能为 迁移 造成障碍。设想,现在有一个 bouncing ball 1 的 GUI 程序,或者一个 简单展示文字的程序 1 ,那么 如何让它在 windows, linux, mac 上成功运行?

这是一个问题。迁移成功,是最终结果。关键词(设想你是一个 win 桌面软件开发者 现在像借助 .NET Core 让你的软件可以跨平台运行):port windows form to mac linux (你的思路是,WinVer.NET->MacVer.Mono->MacVer.NETCore)

(然后你会发现,.NET core 是作为一个 ‘服务器端语言’ 跨平台的,并不是作为一个 ‘客户端语言’ 跨平台的。它不是 Java 那样有官方支持的客户端跨平台的解决方案如 Java Swing 和 JavaFX ,它只有类似 AvaloniaUI 1 2 这样的第三方包 来做 GUI ) —— 这段 Windows form 代码 或 这段 你别指望在 linux mac 上能跑

TBC
only runs on Windows
WinForms only runs on Windows 1
Windows Compatibility Pack package only runs on Windows 2

SDK 与平台

目前,作为 C# 有这样 6 个编译器 (C# compiler):

  • WinVer.NET (即 .NET Framework)
  • LinuxVer.Mono
  • MacVer.Mono
  • WinVer.NETCore
  • LinuxVer.NETCore
  • MacVer.NETCore

说明0:
程序 <= 编译成功 <= 依赖包 <= code <= 平台 <= Engine SDK <= SDK <= 编译器

Adobe Air, Java Swing, Java JavaFX 1 都是跨平台 UI 的解决方案

.NET Core 目前是作为一个网站服务器端的解决方案 ‘跨平台’ 的,并非 C/S客户端软件的跨平台 1

概念: “跨平台”:服务器端跨平台、客户端跨平台

说明1:
C# 编译器 (C# compiler)
当你有一份代码文件,通过 C# 编译器,你可以得到二进制文件,然后 运行此文件,你可以得到程序运行结果。lyrics.cs 1 的例子:

csc lyrics.cs
mono lyrics.exe
然后你会看到软件界面的结果

说明2:
.NET Standard 的概念对于迁移是无用的。
这些编译器,都有遵守 .NET Standard [1](),都是 .NET 实现。但是 这是否代表,只要任何一个遵守 .NET Standard 的实现的编译器,都能让 一份代码在此编译器上跑? NO.
一个最简单的例子:编译出来的程序,是 32 位 or 64 位? 在 mac 系统上,当你使用 32 位程序时,mac 10.13.4 (macOS High Sierra) 以及更新的系统会警示你:mac 即将放弃对于 32 位程序的支持,也就是 所有程序都必须是 64 位程序 1。

说明3:
32位 or 64位?
当你使用 C# 编译器的时候,有些 C# 编译器 会明确告诉你,有部分的 C# SDK 只支持 32 位。比如 MacVer.Mono 的 System.Drawing 部分 1。这个叫做 compatibility 。这也作证了,为什么说 .NET Standard 其实没啥用:遵守了 .NET Standard 之后一个软件该瘫痪还是会瘫痪。
mono compatibility 1

说明4:
语言的歧义性、标题与受众:
《从 .NET 迁移到 .NET Core ... 》 这文章是给谁看的?

  • 一般这样的文章,给一个 Win 使用者就会津津有味地读起来,或许有参考价值
  • 一般这样的文章,给一个 linux 使用者就会津津有味地读起来,最后发现,原来是 WinVer.NET 迁移到 WinVer.NETCore ,和 LinuxVer.NETCore 根本没有参考价值 (至少中间还隔着 Linux 系统、LinuxVer.Mono )

所以 正确的标题是:
《从 WinVer.NET 迁移到 WinVer.NETCore ... 》
《从 LinuxVer.Mono 迁移到 LinuxVer.NETCore ... 》
// 然而,基本上没人会这么做。MS 的 Richard 的所有谈论 .NET Core 的文章 1 2,.NET Conf 1 2,全都没有明确 scope :它基本上都是给 《从 WinVer.NET 迁移到 WinVer.NETCore ... 》 的关注者们看的。

The entire conf is devoted to new release of .NET Core 3.0 covering all the aspects of web, desktop and mobile development on Core 1 --- @WinVer.NETCore

How to: Port a Windows Forms desktop app to .NET Core (with Windows Compatibility Pack only runs on Windows) 1 --- from WinVer.NET to WinVer.NETCore

简言之,.NET Core 的大戏,除非明确说明,皆可默认是 Windows 关注者的自娱自乐。一场大戏,和 Linux 与 mac 无关的。10篇文章里只有1篇提及了

  • LinuxVer.Mono
  • MacVer.Mono
  • LinuxVer.NETCore
  • MacVer.NETCore

然而这才是 linux 关注者所应该看的,这才是不会给 linux 关注者 浪费时间的。10篇文章里只有1篇。

说明4:
C# 桌面程序,什么是微软官方推荐的开发办法?
C# 的爸爸是微软,那么 我们看看什么才是微软官方推荐的 C# 用法。尽管各路 hack 都能使用 C# 但如果有官方推荐的路径 最好还是走官方推荐。这里可以从 .NET Conf 管窥一斑 1

桌面软件 x win: WinForms or WPF or UWP @WinVer.NETCore // Windows Desktop App 布道师 Olia Gavrysh 1 2 1 2
桌面软件 x linux: Xamarin.Forms @LinuxVer.NETCore
桌面软件 x mac: Xamarin.Forms @MacVer.NETCore // Xamarin 布道师 Maddy Leger 1 2 3 David Ortinau 1 2
服务器软件 x win: Blazor @WinVer.NETCore // Web App 布道师 Daniel Roth
服务器软件 x linux:
服务器软件 x mac:

典型的,不是微软官方推荐的路径 (可被上述路径代替:不被官方推荐 或根本是过时):
桌面软件 x win: WinForms or WPF @WinVer.NET // 微软官方奉为过时
桌面软件 x linux: Avalonia UI (mono, .NET Core) // 微软官方未提及
桌面软件 x mac: Xamarin.Forms @MacVer.Mono
服务器软件 x win: ASP.NET @WinVer.NET // Legacy
服务器软件 x linux: ASP.NET @LinuxVer.Mono // 无 async 语法支持
服务器软件 x mac: ASP.NET @MacVer.Mono // 无 async 语法支持

说明5:
bouncing ball 程序有几种写法?
1:
InitializeComponent() SolidBrush()
in Namespace: System.Drawing
using System.Windows.Forms
例子 https://www.youtube.com/watch...

-

TBC

  • Windows Compatibility Pack (for WinVer.NETCore) 1 2 3
  • migration 1 2
  • lyrics.cs 1
  • bouncingBall.cs 1
  • Visual Studio for Mac 1 2

TBC

  • System.Drawing.Common 1 2
  • libgdiplus 1
  • System.Windows.Forms 在 linux 和 mac 的不可用性 1 2 , 这段 Windows form 代码你别指望在 linux mac 上能跑
  • libgdiplus, Avalonia 在 linux 和 mac 的可用性 1 2 3 ,这让人想起了 JavaFX 1
  • 如果把 dotnet core 看作一门全新的语言 (C# 的方言),那么 可以直接问: what is some awesome things you can do with dotnet core? awesome-dotnet-core (基本上等于 .NET 除去和 Windows系统绑定得很深的部分,因为 .NET 和 Windows 系统绑定得很深的部分,是确实存在的(比如IIS, System.Drawing, System.Windows.Forms 1, KeyEventHandler, Button, MessageBox, Form, TreeViewEventHandler 1 ),这部份呢 在 linux 和 mac 上 你用不到/用不了 ) (如果有更新:C# dotnet core GUI linux - Google 搜索)
  • C# windows form application linux
  • port C# windows form application to linux
  • 社区小白鼠同僚支持 1
  • 按照不要尝鲜 不要当小白鼠 (只支持经过时间检验的东西)的原则:dotnet core 出现之前的、经过时间检验的(已有投入使用至少一到两年 因为可被称谓“老牌成熟解决方案” 已经支持过开发比较大的工程规模的软件了? 把吃螃蟹的事情交给别人做 ) 的老牌方案 1 2,比如 CrazyTalk Animator 这是一个老牌软件 它选择的是一个工业级的解决方案:桌面软件 + C# + 跨平台 的组合之下,它选择的 wrapper 是 GTK# 。
  • 迁移工程师:
  • 在迁移工程师的角度:把 linux 原生软件 port 到 win 平台,和 把 win 平台原生软件 port 到 linux 平台,是不同的,虽然 最后得到的都是一个 跨平台软件,但是囿于 他们的 优先支持平台是不同的,也会各异。
  • 在迁移工程师的角度:以 linux mac 为 ‘优先支持平台’ 的跨平台软件,也即:一个开发出来的软件 是从头到尾(从开发到部署)在 linux (mac) 平台上的 (即使对于 win 平台有支持,也仅仅是附属品:在支持好了 linux (mac) 平台之后,再去支持 win 平台)(而不是 支持好了 win 平台,再去支持 linux (mac) 平台)
  • 除非一个 framework 最开始的设计 就是跨平台的 (底层的 wrapper 从设计思想上 就是跨平台的,即 允许开发者不用亲自去处理跨平台的细节),比如 应用层面的 Electron, 比如 编译层面的 JVM,比如 build 层面的 Golang 1 2 ,比如 virtual machine runtime 层面的 Java 1 C# ,比如 runnable executable binary (compile to native code 而不需要 VM-bytecode/MSIL 作为 intermediary language 的支持) 层面的 C/C++ 1, Delphi 1 2 , Golang 1 2。
  • 在 “一个 framework 最开始的设计 就是跨平台的” 的方面, dotnet core C# GUI (吹的最响的也就是 Avalonia 了吧?) 甚至不如 golang + golang QT binding ,更不如 Java Swing / JavaFX ,C#+GTK# 1,Delphi 1 2 3 4 这种老牌方案了。
  • 在 “一个 framework 最开始的设计 就是跨平台的” 的方面,一个对于跨平台 GUI 软件开发在使用 QT Binding 方面的建议(QT Binding / GTK Binding 这种玩意 到底靠不靠谱,哪些方面出问题是大概率事件 怎么避免 )
  • 在应用层面 和 Electron 一个级别但并没有借助浏览器的跨平台方案:Delphi 1 2 with FireMonkey® framework 1 。足够老牌 1 。例子 Tomboy notes 1 。

真正的桌面软件 ( 正所谓 “巧妇难为无米之炊”,有了米之后才好做饭
你看有了米之后 做出来的饭菜是如此香甜 ) 1 2

FireMonkey Quick Start Guide - Tutorials - My First FireMonkey Application 1
IDE系统要求(貌似IDE本身不是跨平台的...即使它可以开发linux软件。等于在WinPC开发 在linux上部署)1 下载1

  • 另一观察角度:platform-independent GUI library / wrapper 1 (如 Delphi-FireMonkey, QT-C++, GTK-C++)。它们都是原生:一个 framework 最开始的设计 就是跨平台的 (底层的 wrapper 从设计思想上 就是跨平台的,即 允许开发者不用亲自去处理跨平台的细节)。关于 GTK# 1 ,做到了 老牌+C#+部署跨平台+开发跨平台(dotnet core, 不依赖 Windows ABI),有待研究如何使用 。

备选 (dotnet core GTK):picoe/Eto
讨论 小白鼠 1 2 3
可行性 1 2 3 4

platform-independent GUI library / wrapper:
GTK#, picoe/Eto, Avalonia



2019.9.16
另一种思路 看这些 GUI 解决方案 (假设你要 开始写一个 IDE 比如 Xamarin Studio IDE 或 Delphi RAD Studio 那样的大型桌面软件,你为之找 GUI SDK / wrapper,参考那些 Software industry 里的成熟的 GUI 解决方案 - 如果选错了那么就无法成功,写了也否则要重写)(并且准备写完之后 把这个软件 卖掉):
要原生
要DE级orIDE级 (成熟 不卡)
进一步,不要操作指针

要原生:

C++ QT, Delphi FireMonkey, C++ GTK, Java 系 Swing JavaFX, C# 系 WPF WinForms Avalonia, NodeJS Electron 
不要任何 binding 比如 GTK# 

要DE级orIDE级 1 1 1 1 观察 MS Visual Studio 是拿 C# Win32 API 写的 (为什么一开始就没把 Win32 API 和 C# 分开呢?可惜可惜) 2 3 4:

C++ QT, Delphi FireMonkey, C++ GTK, // 参考 各个操作系统的界面(Desktop Environment)都是由什么语言写的 (Ubuntu KDE -> C++ Qt, Ubuntu Unity -> C++ QT / C GTK, Ubuntu GNOME 3 -> C GTK, Ubuntu GNOME 2 -> C GTK, linux mint cinnamon(GNOME 3) -> C GTK, mate(GNOME 2)-> C GTK, xfce -> C GTK, FreeBSD GhostBSD mate(GNOME 2) -> C GTK )(IDE Eclipse -> Java SWT, Eclipse -> Java SWT, IntelliJ IDEA -> Java Swing, Microsoft Visual Studio -> C++, C# WPF, MonoDevelop -> C# GTK#, Sublime Text -> C++ Python, VSCode -> NodeJS Electron, TextMate -> Objective-C Cocoa, Notepad++ -> C++, EmEditor -> C++ )

(what is GTK#, and why they don't use it cuz 卖不掉) GTK 是 Proprietary Tech 1
1 2 2

进一步,不要操作指针:

Java SWT, Java Swing, C# WPF WinForms

补充 C# 的使用办法: mono + .NET Core 双开 (既然两个无法替代彼此 那么最好的选择就是双开,外加一个 类似 jenv 的切换工具 )
1
mono 开发近况 2

-

你可能感兴趣的:(c#)