作者 | Nate Hill 译者 | 弯月
出品 | CSDN(ID:CSDNnews)

TypeScript非常优秀。它完美地结合了强类型和快速开发,因此非常好用,我在许多情况下都会默认选择这个库。但是,世上没有完美的语言,有些情况下TypeScript并不是最合适的工具:

  • 性能至关重要(例如实时通信、视频游戏)
  • 需要与原生代码(如C/C++或Rust)交互
  • 需要更严格的类型系统(例如金融系统)

对于这些情况,TypeScript开发人员最好还是选用其他语言。C#、Go和Java都是非常好的选择。它们的速度远超 TypeScript,每种语言都有自己的长处。C#能与TypeScript配合得很好,我来解释一下为什么。

图源:CSDN 付费下载自东方 IC

TypeScript 就是添加了 C# 的 JavaScript

C#能与TypeScript配合得很好,因为它们看上去就像是同一种语言。两者都是由Anders Hejlsberg设计的,而且从许多方面来看,TypeScript就是添加了C#的JavaScript。它们的特性和语法都很相似,因此在同一个项目中结合使用二者非常容易。更重要的是,C#的语言与TypeScript很相似,因此开发人员阅读和编写代码也非常轻松。

相反,Go是一种完全不同的语言:没有类,没有继承,没有异常,没有包级别的封装(只有类级别的封装),而且语法也完全不同。当然这并不一定是坏事,但开发人员的确需要重新思考并用不同的方式设计代码,因此,同时使用Go和TypeScript是比较困难的。不过,Java与C#很相似,但依然缺乏许多C#和TypeScript都有的功能。

C#和TypeScript的相似之处

也许你已经知道,C#和TypeScript有很多相似之处,如基于C的语法、类、接口、泛型等。下面,我来详细列举一下二者的相似之处:

  • async/await
  • lambda表达式和函数式数组方法
  • 用于处理空的操作符(?,!,??)
  • 解构
  • 命令行界面(CLI)

async/await

首先,C#和JavaScript都使用async/await来处理异步代码。在JavaScript中,异步操作用Promise表示,而应用程序可以await一个异步操作结束。C#中的Promise其实是Task,概念上与Promise完全相同,也有相应的方法。下面的例子演示了两种语言中async/await的用法:

async function fetchAndWriteToFile(url: string, filePath:string): Promise<string> {// fetch() returns aPromiseconst response = awaitfetch(url);const text = awaitresponse.text();// By the way, we'reusing Deno (https://deno.land)awaitDeno.writeTextFile(filePath, text);return text;
}

TypeScript中async/await的例子

using System.IO;
using System.Net.Http;
using System.Threading.Tasks;async Task<string> FetchAndWriteToFile(string url, stringfilePath) {// HttpClient.GetAsync()returns a Taskvar response = await newHttpClient().GetAsync(url);var text = awaitresponse.Content.ReadAsStringAsync();awaitFile.WriteAllTextAsync(filePath, text);return text;
}

C#中async/await的例子

下面是JavaScript的Promise API与等价的C# Task API:

JavaScript API Equivalent C# API
Promise.prototype.then() Task.ContinueWith()
new Promise() new TaskCompletionSource()
Promise.resolve() Task.FromResult()
Promise.reject() Task.FromException()
Promise.all() Task.WhenAll()
Promise.race() Task.WhenAny()

Lambda表达式和函数式数组方法

C#和JavaScript都用熟悉的=>语法(即箭头函数)来表示lambda表达式。下面是TypeScript和C#的比较:

const months = ['January', 'February', 'March', 'April'];
const shortMonthNames = months.filter(month => month.length< 6);
const monthAbbreviations = months.map(month =>month.substr(0, 3));
const monthStartingWithF = months.find(month => {returnmonth.startsWith('F');
});

TypeScript中使用lambda表达式

using System.Collections.Generic;
using System.Linq;var months = new List<string> {"January","February", "March", "April"};
var shortMonthNames = months.Where(month => month.Length <6);
var monthAbbreviations = months.Select(month =>month.Substring(0, 3));
var monthStartingWithF = months.Find(month => {returnmonth.StartsWith("F");
});

C#中使用lambda表达式

上述示例演示了C#的System.Linq命名空间中的一些方法,相当于JavaScript的函数式数组方法。下面是JavaScript的数组方法与等价的C# Linq方法:

JavaScript API Equivalent C# API
Array.prototype.filter() Enumerable.Where()
Array.prototype.map() Enumerable.Select()
Array.prototype.reduce() Enumerable.Aggregate()
Array.prototype.find() List.Find()
Array.prototype.findIndex() List.FindIndex()
Array.prototype.every() Enumerable.All()
Array.prototype.some() Enumerable.Any()
Array.prototype.flatMap() Enumerable.SelectMany()

处理空操作符

C#和TypeScript处理空的特性也一样:

Feature name Syntax Documentation links
Optional properties property? TS / C#
Non-null assertion object!.property TS / C#
Optional chaining object?.property JS / C#
Nullish coalescing object ?? alternativeValue JS / C#

解构

尽管C#默认不支持数组或类的解构,但它支持Tuple和Record的解构,用户也可以为自定义类型定义解构。下面是TypeScript和C#中解构的例子:

const author = { firstName: 'Kurt', lastName: 'Vonnegut' };
// Destructuring an object:
const { firstName, lastName } = author;const cityAndCountry = ['Indianapolis', 'United States'];
// Destructuring an array:
const [city, country] = cityAndCountry;
TypeScript中解构的例子
using System;var author = new Author("Kurt", "Vonnegut");
// Deconstructing a record:
var (firstName, lastName) = author;var cityAndCountry = Tuple.Create("Indianapolis","United States");
// Deconstructing a tuple:
var (city, country) = cityAndCountry;// Define the Author record used above
record Author(string FirstName, string LastName);

C#中解构的例子

命令行界面(CLI)

我的开发方式是使用文本编辑器编写代码,然后在终端运行命令,构建并运行。对于TypeScript,这意味着需要使用node或deno命令行界面(CLI)。C#也有类似的CLI,名为dotnet(由C#的.NET运行时得名)。下面是使用dotnet CLI的一些例子:

mkdir app && cd app
# Create a new console application
# List of available app templates:https://docs.microsoft.com/dotnet/core/tools/dotnet-new
dotnet new console
# Run the app
dotnet run
# Run tests (don't feel bad if you haven't written those)
dotnet test
# Build the app as a self-contained
# single file application for Linux.
dotnet publish -c Release -r linux-x64

基本功能(类、泛型、错误和枚举)

这些是TypeScript和C#之间更基本的相似性。下面的例子是有关这几个方面的介绍:

import { v4 as uuidv4 } from'https://deno.land/std/uuid/mod.ts';enum AccountType {Trial,Basic,Pro
}interface Account {id: string;type: AccountType;name: string;
}interface Database<T> {insert(item: T):Promise;get(id: string):Promise<T>;
}class AccountManager {constructor(database:Database<Account>) {this._database =database;}asynccreateAccount(type: AccountType, name: string) {try {const account = {id: uuidv4(),type,name;};awaitthis._database.insert(account);} catch (error) {console.error(`Anunexpected error occurred while creating an account. Name: ${name}, Error:${error}`);}}private _database:Database<Account>;
}

TypeScript类的示例

using System;
using System.Threading.Tasks;enum AccountType {Trial,Basic,Pro
}record Account(string Id, AccountType Type, string Name);interface IDatabase<T> {Task Insert(T item);Task<T> Get(stringid);
}class AccountManager {publicAccountManager(IDatabase<Account> database) {_database = database;}public async voidCreateAccount(AccountType type, string name) {try {var account = newAccount(Guid.NewGuid().ToString(),type,name);await_database.Insert(account)} catch (Exceptionexception) {Console.WriteLine($"An unexpected error occurred while creating anaccount. Name: {name}, Exception: {exception}");}}IDatabase<Account>_database;
}

C#类的示例

C#的其他优势

与TypeScript相似并不是C#的唯一优点,它还有其他优点:

  • 与原生代码结合更容易
  • 事件
  • 其他功能

与原生代码结合

C#的最大优势之一就是它可以深入原生代码。本文开头提到,TypeScript并不擅长与C/C++代码结合。Node.js有一个支持原生C/C++的插件,名为Node-API,但是它需要为原生函数编写额外的C++包裹器,将原生类型转换成JavaScript对象,或相反,类似于JNI的工作方式。而C#可以直接调用原生函数,只需把库放到应用程序的bin目录下,然后将API定义为C#中的外部函数即可。然后就能像C#函数一样使用外部函数,.NET运行时会处理好C#数据类型与原生数据类型之间的转换。例如,如果原生库导出了下面的C函数:

int countOccurrencesOfCharacter(char *string, char character) {int count = 0;for (int i = 0;string[i] != '\0'; i++) {if (string[i] ==character) {count++;}}return count;
}

那么可像下面这样从C#中调用:

using System;
using System.Runtime.InteropServices;var count = MyLib.countOccurrencesOfCharacter("C# is prettyneat, eh?", 'e');
// Prints "3"
Console.WriteLine(count);class MyLib {// Just placeMyLibraryName.so in the app's bin folder[DllImport("MyLibraryName")]public static externint countOccurrencesOfCharacter(string str, char character);
}

这种方法可以通过C连接访问任何动态库(.so、.dll或.dylib),也就是说,你可以轻松地调用C、C++、Rust、Go或其他语言编写的代码,只要编译成机器码即可。原生交互的其他应用还有:

  • 将指针作为IntPtr传给原生对象
  • 利用GetFunctionPointerForDelegate()将C#方法作为函数指针传给原生函数
  • 使用Marshal.PtrToStringAnsi()将C字符串转换为C#字符串
  • 转换结构和数组

事件

C#的一个独特的特性是,提供了一流的事件支持。在TypeScript中,你可以实现addEventListener()方法,让客户端监听事件,而C#有event关键字,可以用来定义事件,并通过简单的语法将事件通知给所有监听者(而不需要像TypeScript那样手动遍历所有事件监听者并在try/catch块中执行)。例如,我们可以让Connection类定义一个MessageReceived事件,如下所示:

class Connection {// AnAction<string> is a callback that accepts a string parameter.public eventAction<string> MessageReceived;
}

使用Connection代码可以通过+=操作符给MessageReceived添加一个处理函数,如下:

var connection = new Connection();
connection.MessageReceived += (message) => {Console.WriteLine("Message was received: " + message);
};

而Connection类可以在内部调用MessageReceived,为所有监听者触发MessageReceived事件:

// Raise the MessageReceived event
MessageReceived?.Invoke(message);

其他优势

  • 性能:C#很快。C#的ASP.NET Web框架一直在Techempower的评测中名列前茅,而C#的.NET CoreCLR运行时的性能每个主要版本都在提高。C#拥有优良性能的原因之一是,通过使用结构而不是类,应用程序可以最小化甚至完全消除垃圾回收。因此,C#在视频游戏编程中非常流行。

  • 游戏和混合现实:C#是游戏开发最流行的语言之一,像Unity、Godot甚至Unreal游戏引擎都使用了C#。C#在混合现实中也很流行,因为VR和AR应用程序都是用Unity编写的。

  • 由于C#拥有第一方库、工具和文档,因此一些任务非常容易实现,比如,在C#中创建gRPC客户端要比 TypeScript方便得多。相反,在Node.js中使用TypeScript时,就必须找出正确的模块和工具的组合,才能正确地生成JavaScript gRPC客户端,以及相应的TypeScript类型。

  • 高级功能:C#有许多其他语言没有的功能,如运算符重载、析构函数等。

总结

如前所述,世上没有完美的语言。在设计语言时总要有所权衡,所以一些语言的速度更快,但使用难度会增加(例如Rust的借出检查)。另一方面,一些语言非常易用,但通常性能的优化难度就会增加(例如JavaScript的动态语言特性)。正因如此,我相信掌握一组相似的语言会非常有用:这些语言分别有各自的长处,但都很相似,而且能互相配合。例如,下面是我选择的一组语言:

TypeScript

  • 最高层的语言,开发速度最快

  • 性能并非最佳,但适用于大多数应用

  • 不太适合与原生代码结合

C#

  • 仍然是高级语言,支持垃圾回收,所以很容易使用,尽管并不如TypeScript那么容易。

  • 从速度和内存占用量来看,其性能都优于 TypeScript

  • 最重要的是,能够与底层很好地结合

C++

  • 开发难度较大(例如需要手动内存管理),因此开发速度会慢很多

  • 但运行时的性能最佳!而且随处可用,能与许多已有的软件相结合

  • 很像C#,而且标准库很好,但也有许多陷阱(大多数与内存管理有关)。我更希望使用Rust,因为它的内存安全性更好,但我的许多工作都要与已有的C++代码结合,因此使用C++会更容易。

参考链接:https://nate.org/csharp-and-typescript

C# 是 TypeScript 的最好替补?相关推荐

  1. 正式对标苹果,小米 12 系列三箭齐发,MIUI 欲成为跨设备操作系统!

    保持热爱,共赴山海! 作者 |苏宓 出品 | CSDN(ID:CSDNnews) 12 月 28 日,依旧是 19:30,小米新品发布会正式拉开帷幕. 在这场发布会上,小米新品"吸睛无数&q ...

  2. 超简单的react和typescript和引入scss项目搭建流程

    1.首先我们先创建一个react项目,react官网也有react项目搭建的命令 npx create-react-app my-app cd my-app 2.安装我们项目需要的样式依赖,这个项目我 ...

  3. 老码农绝密:使用 TS(TypeScript) 的 10 大理由

    最近,小编读了一篇名为<放弃 TypeScript 的 7 个非常好的理由>,这篇文章的阅读量不低.里面有些观点确实有趣,不过在这里我要向你介绍使用 TypeScript 的 10 个理由 ...

  4. 设置WebStorm像VSCode一样每行代码结尾自动格式化加入“;”分号(JavaScript、TypeScript格式化)

    Ctrl+Shift+S→编辑器→Code Style→JavaScript或TypeScript→Punctuation 1.每行代码结尾自动加上;分号: Use(下拉框选Use)semiconlo ...

  5. 为TypeScript项目生成API文档

    为TypeScript项目生成文档 使用typedoc为TypeScript项目生成API文档. 1. 使用typedoc生成HTML文档 需要安装 typedoc. npm i typedoc 可以 ...

  6. TypeScript 1

    TypeScript 的由来 TypeScript 是 JavaScript 的一个超集,支持 ECMAScript 6 标准. TypeScript 由微软开发的自由和开源的编程语言. TypeSc ...

  7. TypeScript学习笔记之 接口(Interface)

    在java中,接口是用来定义一些规范,使用这些接口,就必须实现接口中的方法,而且接口中的属性必须是常量. javascript中是没有接口的概念的.所以TypeScript在编译成 JavaScrip ...

  8. c# typescript_在任何IDE中从C#,Java或Python代码获取TypeScript接口的简单方法

    c# typescript by Leonardo Carreiro 莱昂纳多·卡雷罗(Leonardo Carreiro) 在任何IDE中从C#,Java或Python代码获取TypeScript接 ...

  9. 如何在React中使用Typescript

    TypeScript can be very helpful to React developers. TypeScript对React开发人员可能非常有帮助. In this video, Ben ...

最新文章

  1. 王者荣耀AI绝悟如何选英雄?腾讯AI Lab新研究揭秘
  2. 陈天奇:深度学习编译技术的现状和未来
  3. Struts2/WebWork高危漏洞(远程执行任意代码)
  4. Py中enumerate方法【转载】
  5. pytorch 吸烟检测yolov5s
  6. qt 调用qpainter_在Qt5.4中如何实现QOpenGLWidget和QPainter混合编程
  7. VS Code 中的文件添加图标的插件vscode-icons
  8. 搭建cacti监控平台
  9. 凯撒密码加密算法python_信息安全与密码学的关系
  10. WWW 2017精选论文
  11. 如何制作启动U盘安装系统?
  12. 虚幻引擎4简介,UE4简介--这是一个强大的游戏开发引擎
  13. 二级渠道分销系统开发适合什么样的产品?
  14. Nand Flash管理算法介绍之FTL简介
  15. 航空航天空气动力学高性能计算解决方案
  16. 美图旗下美妆平台将停止运营 COO:All in “美和社交”
  17. 数学之美—泰勒展开式
  18. 口算练习机/儿童数学宝/口算神器 开发方案,LCD液晶显示驱动IC-VK1621B,可提供方案/技术支持
  19. 成都百知教育跨境电商告诉你什么是海关数据,如何使用海关数据
  20. lavaral中文手册_Laravel-mix 中文文档

热门文章

  1. leetcode770. Basic Calculator IV
  2. 彻底理解Python切片
  3. FTP的主、被动模式
  4. LeetCode 415. 字符串相加 (逢十进一模版字符处理)
  5. C++多态(二)——纯虚函数、抽象类
  6. 【多线程】CountDownLatch 和 CyclicBarrier:如何让多线程步调一致?
  7. 安装k8s,高可用3 master安装脚本
  8. 四类文法以及上下文有(无)关的理解【转】
  9. a = a + 1, a++, ++a ,a+=1区别在哪
  10. THUWC2017 随机二分图