<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          C# 是 TypeScript 的最佳替補?

          共 9492字,需瀏覽 19分鐘

           ·

          2022-03-16 04:07

          作者 | Nate Hill

          譯者 | 彎月

          出品 | CSDN(ID:CSDNnews)

          TypeScript非常優(yōu)秀。它完美地結合了強類型和快速開發(fā),因此非常好用,我在許多情況下都會默認選擇這個庫。但是,世上沒有完美的語言,有些情況下TypeScript并不是最合適的工具:

          1. 性能至關重要(例如實時通信、視頻游戲)
          2. 需要與原生代碼(如C/C++或Rust)交互
          3. 需要更嚴格的類型系統(tǒng)(例如金融系統(tǒng))

          對于這些情況,TypeScript開發(fā)人員最好還是選用其他語言。C#、Go和Java都是非常好的選擇。它們的速度遠超 TypeScript,每種語言都有自己的長處。C#能與TypeScript配合得很好,我來解釋一下為什么。

          圖源:CSDN 付費下載自東方 IC

          1. TypeScript 就是添加了 C# 的 JavaScript

          C#能與TypeScript配合得很好,因為它們看上去就像是同一種語言。兩者都是由Anders Hejlsberg設計的,而且從許多方面來看,TypeScript就是添加了C#的JavaScript。它們的特性和語法都很相似,因此在同一個項目中結合使用二者非常容易。更重要的是,C#的語言與TypeScript很相似,因此開發(fā)人員閱讀和編寫代碼也非常輕松。相反,Go是一種完全不同的語言:沒有類,沒有繼承,沒有異常,沒有包級別的封裝(只有類級別的封裝),而且語法也完全不同。當然這并不一定是壞事,但開發(fā)人員的確需要重新思考并用不同的方式設計代碼,因此,同時使用Go和TypeScript是比較困難的。不過,Java與C#很相似,但依然缺乏許多C#和TypeScript都有的功能。

          2. C#和TypeScript的相似之處

          也許你已經(jīng)知道,C#和TypeScript有很多相似之處,如基于C的語法、類、接口、泛型等。下面,我來詳細列舉一下二者的相似之處:

          • 2.1 async/await
          • 2.2 lambda表達式和函數(shù)式數(shù)組方法
          • 2.3 用于處理空的操作符(?,!,??)
          • 2.4 解構
          • 2.5 命令行界面(CLI)
          • 2.6 基本功能(類、泛型、錯誤和枚舉)

          2.1 async/await

          首先,C#和JavaScript都使用async/await來處理異步代碼。在JavaScript中,異步操作用Promise表示,而應用程序可以await一個異步操作結束。C#中的Promise其實是Task,概念上與Promise完全相同,也有相應的方法。下面的例子演示了兩種語言中async/await的用法:

          TypeScript中async/await的例子:

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

          C#中async/await的例子:

          using?System.IO;
          using?System.Net.Http;
          using?System.Threading.Tasks;

          async?Task<string>?FetchAndWriteToFile(string?url,?stringfilePath)?{
          ??//?HttpClient.GetAsync()returns?a?Task
          ??var?response?=?await?newHttpClient().GetAsync(url);
          ??var?text?=?awaitresponse.Content.ReadAsStringAsync();
          ??awaitFile.WriteAllTextAsync(filePath,?text);
          ??return?text;
          }

          下面是JavaScriptPromise API與等價的C# Task API:

          JavaScript API等價的C# API
          Promise.all()Task.WaitAll()
          Promise.resolve()Task.FromResult()
          Promise.reject()Task.FromException()
          Promise.prototype.then()Task.ContinueWith()
          new Promise()new TaskCompletionSource()

          2.2 Lambda表達式和函數(shù)式數(shù)組方法

          C#JavaScript都用熟悉的=>語法(即箭頭函數(shù))來表示lambda表達式。下面是TypeScriptC#的比較:

          TypeScript中使用lambda表達式:

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

          C#中使用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#System.Linq命名空間中的一些方法,相當于JavaScript函數(shù)式數(shù)組方法。下面是JavaScript數(shù)組方法與等價的C# Linq方法:

          JavaScript API等價的C# API
          Array.prototype.filter()Enumerable.Where()
          Array.prototype.map()Enumerable.Select()
          Array.prototype.reduce()Enumerable.Aggregate()
          Array.prototype.every()Enumerable.All()
          Array.prototype.find()List.Find()
          Array.prototype.findIndex()List.FindIndex()

          2.3 處理空操作符

          C#和TypeScript處理空的特性也一樣:

          Feature nameSyntaxDocumentation links
          Optional propertiesproperty?TS :https://www.typescriptlang.org/docs/handbook/2/objects.html#optional-properties,
          C#:https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/nullable-reference-types
          Non-null assertionobject!.propertyTS:https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-0.html#non-null-assertion-operator,
          C#:https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/null-forgiving
          Optional chainingobject?.propertyJS :https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining,
          C#:https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/member-access-operators#null-conditional-operators--and-
          Nullish coalescingobject ?? alternativeValueJS:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_operator,
          C#:https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/null-coalescing-operator

          2.4 解構

          盡管C#默認不支持數(shù)組或類的解構,但它支持Tuple和Record的解構,用戶也可以為自定義類型定義解構。下面是TypeScript和C#中解構的例子:

          TypeScript中解構的例子:

          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;

          C#中解構的例子:


          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);

          2.5 命令行界面(CLI)

          我的開發(fā)方式是使用文本編輯器編寫代碼,然后在終端運行命令,構建并運行。對于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

          2.6 基本功能(類、泛型、錯誤和枚舉)

          這些是TypeScript和C#之間更基本的相似性。下面的例子是有關這幾個方面的介紹:

          TypeScript類的示例:

          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?{
          ??insert(item:?T):Promise;
          ??get(id:?string):Promise;
          }

          class?AccountManager?{

          ??constructor(database:Database)?{
          ????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;
          }

          C#類的示例:

          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?Get(stringid);
          }

          class?AccountManager?{

          ??publicAccountManager(IDatabase?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_database;
          }

          3. C#的其他優(yōu)勢

          與TypeScript相似并不是C#的唯一優(yōu)點,它還有其他優(yōu)點:

          • 3.1 與原生代碼結合更容易
          • 3.2 事件
          • 3.3 其他功能

          3.1 與原生代碼結合

          C#的最大優(yōu)勢之一就是它可以深入原生代碼。本文開頭提到,TypeScript不擅長與C/C++代碼結合Node.js有一個支持原生C/C++的插件,名為Node-API,但是它需要為原生函數(shù)編寫額外的C++包裹器,將原生類型轉(zhuǎn)換成JavaScript對象,或相反,類似于JNI的工作方式。而C#可以直接調(diào)用原生函數(shù),只需把庫放到應用程序的bin目錄下,然后將API定義為C#中的外部函數(shù)即可。然后就能像C#函數(shù)一樣使用外部函數(shù),.NET運行時會處理好C#數(shù)據(jù)類型與原生數(shù)據(jù)類型之間的轉(zhuǎn)換。例如,如果原生庫導出了下面的C函數(shù):

          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#中調(diào)用:

          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連接訪問任何動態(tài)庫(.so.dll.dylib),也就是說,你可以輕松地調(diào)用CC++RustGo其他語言編寫的代碼,只要編譯成機器碼即可。原生交互的其他應用還有:

          • 將指針作為IntPtr傳給原生對象
          • 利用GetFunctionPointerForDelegate()C#方法作為函數(shù)指針傳給原生函數(shù)
          • 使用Marshal.PtrToStringAnsi()C字符串轉(zhuǎn)換為C#字符串
          • 轉(zhuǎn)換結構和數(shù)組

          3.2 事件

          C#的一個獨特的特性是,提供了一流的事件支持。在TypeScript中,你可以實現(xiàn)addEventListener()方法,讓客戶端監(jiān)聽事件,而C#event關鍵字,可以用來定義事件,并通過簡單的語法將事件通知給所有監(jiān)聽者(而不需要像TypeScript那樣手動遍歷所有事件監(jiān)聽者并在try/catch塊中執(zhí)行)。例如,我們可以讓Connection類定義一個MessageReceived事件,如下所示:

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

          使用Connection代碼可以通過+=操作符給MessageReceived添加一個處理函數(shù),如下:

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

          Connection類可以在內(nèi)部調(diào)用MessageReceived,為所有監(jiān)聽者觸發(fā)MessageReceived事件:

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

          4. 其他優(yōu)勢

          1. 性能: C#很快。C#ASP.NET(Core) Web框架一直在Techempower的評測中名列前茅,而C#.NET CoreCLR運行時的性能每個主要版本都在提高。C#擁有優(yōu)良性能的原因之一是,通過使用結構而不是類,應用程序可以最小化甚至完全消除垃圾回收。因此,C#視頻游戲編程中非常流行。
          2. 游戲和混合現(xiàn)實: C#是游戲開發(fā)最流行的語言之一,像UnityGodot甚至Unreal游戲引擎都使用了C#C#混合現(xiàn)實中也很流行,因為VRAR應用程序都是用Unity編寫的。
          3. 由于C#擁有第一方庫、工具和文檔,因此一些任務非常容易實現(xiàn),比如,在C#中創(chuàng)建gRPC客戶端要比TypeScript方便得多。相反,在Node.js中使用TypeScript時,就必須找出正確的模塊和工具的組合,才能正確地生成JavaScript gRPC客戶端,以及相應的TypeScript類型。
          4. 高級功能:C#有許多其他語言沒有的功能,如運算符重載析構函數(shù)等。

          5. 總結

          如前所述,世上沒有完美的語言。在設計語言時總要有所權衡,所以一些語言的速度更快,但使用難度會增加(例如Rust的借出檢查)。另一方面,一些語言非常易用,但通常性能的優(yōu)化難度就會增加(例如JavaScript的動態(tài)語言特性)。正因如此,我相信掌握一組相似的語言會非常有用:這些語言分別有各自的長處,但都很相似,而且能互相配合。例如,下面是我選擇的一組語言:

          5.1 TypeScript

          • 最高層的語言,開發(fā)速度最快
          • 性能并非最佳,但適用于大多數(shù)應用
          • 不太適合與原生代碼結合

          5.2 C#

          • 仍然是高級語言,支持垃圾回收,所以很容易使用,盡管并不如TypeScript那么容易。
          • 從速度和內(nèi)存占用量來看,其性能都優(yōu)于 TypeScript
          • 最重要的是,能夠與底層很好地結合

          C++

          • 開發(fā)難度較大(例如需要手動內(nèi)存管理),因此開發(fā)速度會慢很多
          • 但運行時的性能最佳!而且隨處可用,能與許多已有的軟件相結合
          • 很像C#,而且標準庫很好,但也有許多陷阱(大多數(shù)與內(nèi)存管理有關)。我更希望使用Rust,因為它的內(nèi)存安全性更好,但我的許多工作都要與已有的C++代碼結合,因此使用C++會更容易。

          參考鏈接:https://nate.org/csharp-and-typescript

          瀏覽 39
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  www男人的天堂 | 亚洲第一黄色视频 | 中文字幕第50页 | 东北女人挨操内射 | 黄色av免费网站 黄色电影视频在线 |