讓原本的 Class Library 也能跨平台

在實務上可能遇到有些自己寫的 class library,或在 GitHub 上 class library,原本跑在 .NET Framework 上,需要自己 porting 到 .NET Core。本文實際以一個 GitHub 上的 class library 為例,一步一步從 .NET Framework 移植到 .NET Core。

Version


macOS High Sierra 10.13.3
.NET Core SDK 2.1.101
VS Code 1.21.1

User Story


orting00

Nikola Zivkovic 提供一個類神經網路的 class library:Simple Neural Network in C#,但只能跑在 .NET Framework 4.6.1。

Task


該 class library 原本只能跑在 .NET Framework,現在我們即將以此 repository 為練習,一步一步從 .NET Framework 移植到 .NET Core。

下載 Repository


1
$ git clone https://github.com/NMZivkovic/SimpleNeuralNetworkInCSharp

使用 git clone 將整個 repository clone 下來。

orting00

  1. 將整個 repository clone 下來
  2. SimpleNeuralNetworkInCSharp 目錄下有:
    • NeuralNetworkCSharp.sln:整個 repository 的 solution 檔
    • NeuralNetworkCSharp:class library 的 project
    • NeuralNetworkCSharpTests:class library 的 unit test project

雖然我們不知道此 repository 在做什麼,不過由於它自帶 Unit Test,我們的目的就是讓所有的 Unit Test 在 .NET Core 下都 綠燈 通過測試

重建 NeuralNetworkCSharp


因為 .NET Core 對 csproj 的 XML 格式有改,我們就不直接從 .NET Framework 的 csproj 升級上來,而是選擇建立新的 csproj,再將所有 C# 檔案複製過來。

建立 MyClassLib

1
$ dotnet new classlib -o MyClassLib

使用 dotnet new classlib 建立新的 class library 專案。

orting00

  1. 輸入 dotnet new classlib -o MyClassLib 建立 MyClassLib 專案。

複製 cs 檔案

orting00

將原來 NeuralNetworkCSharp 專案下的檔案複製到 MyClassLib,除了 csproj 不要複製外,其他檔案全部複製。

orting00

  1. 將複製的檔案貼到 MyClassLib 目錄下
  2. 將原本的 Class1.cs 刪除

編譯專案

1
~/MyClassLib $ dotnet build

使用 dotnet build 編譯 MyClassLib

orting00

  1. 輸入 dotnet build 編譯專案
  2. 出現 Duplicate attribute 錯誤

原本 Properties/Assembly.Info 的一些 attribute 設定,目前已經由 .NET Core 自行設定,因此才會出現 duplicate

Properties/AssemblyInfo.cs

1
2
3
4
5
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

[assembly: InternalsVisibleTo("MyTest")]

將其他 assembly 全部刪除,只留下 InternalsVisibleTo(),並改成 MyTest

因為 MyClassLib 的一些 class 使用了 internal properties,根據 C# 規定,只有相同 assembly 才能存取 internal,但 MyTest 因為不同 assembly,會造成單元測試失敗,故特別設定 InternalsVisibleTo(),讓 MyTest 可以存取 MyClassLibinternal properties

orting00

  1. 重新輸入 dotnet build 編譯
  2. 編譯成功

重建 NeuralNetworkCSharpTests


將使用類似 TDD 方式,依照錯誤訊息逐一解決。

建立 MyTest

1
$ dotnet new mstest -o MyTest

使用 dotnet new mstest 建立新的 Unit Test 專案。

orting00

  1. 輸入 dotnet new mstest -o MyTest 建立 MyTest 專案。

複製 cs 檔案

orting00

將原來 NeuralNetworkCSharpTests 專案下的檔案複製到 MyTest,除了 csproj 不要複製外,其他檔案全部複製。

orting00

  1. 將複製的檔案貼到 MyTest 目錄下
  2. 將原本的 UnitTest1.cs 刪除

執行單元測試

1
~/MyTest $ dotnet test

使用 dotnet test 執行單元測試。

orting01

  1. 輸入 dotnet test 執行單元測試
  2. 一樣出現 Duplicate attribute 錯誤

orting01

Properties/AssemblyInfo.cs 所有內容刪除。

orting01

  1. 在次執行 dotnet test
  2. 出現找不到 Moq namespace 錯誤訊息

Moq 為 .NET 著名的 Mock package,需另外安裝

安裝 Package

orting01

在 NuGet 找的到 Moq,也有 .NET Core 版本。

1
~/MyTest $ dotnet add package moq

使用 dotnet add package 安裝 Moq。

orting01

  1. 輸入 dotnet add package moq 安裝 Moq
  2. Restore 執行 dotnet restore

orting01

  1. 在次執行 dotnet test
  2. 出現找不到 NeuralNetworkCSharp namespace 錯誤訊息

MyTest 要測試 MyClassLib,但目前尚未對 MyClassLib 加入 project reference

加入 Project Reference

1
~/MyTest $ dotnet add reference ../MyClassLib/MyClassLib.csproj

使用 dotnet add referenceMyClassLib 加入 project reference。

orting01

  1. 輸入 dotnet add reference ../MyClassLib/MyClassLib.csprojMyClassLib 加入 project reference

orting01

  1. 再次輸入 dotnet test
  2. 通過 24 個單元測試

其中一個單元測試 skipped,是因為 test code 自己下 [igonre] 不測試,與我們無關

如此我們就順利將 Simple Neural Network in C# 由 .NET Framework 移植到 .NET Core 了。

Summary


要將 .NET Framework 的 class library 移植到 .NET Core,會有以下步驟:

  1. 建立新 project
  2. *.cs 複製過來
  3. dotnet build 會有錯誤訊息
    • AssemblyInfo.cs 的 attribute 拿掉
    • 安裝缺少的 package
    • 新增必要的 project reference
  4. 直到 dotnet test 通過全部測試案例

Conclusion


  • 並不是所有 .NET Framework 的 class library 都能移植到 .NET Core,因為目前 .NET Core 只實做了約一半的 .NET Framework API,且不是所有的 package 都有 .NET Core 版本
  • 類似 TDD 方式,先執行 dotnet builddotnet test,由解決錯誤訊息而逐步完成移植
  • 實務上建議先對原本的 class library 補上 Unit Test,再以移植後 Unit Test 全部 綠燈 作為移植成功的依據

Sample Code


完整的範例可以在我的 GitHub 上找到

Reference


Nikola Zivkovic, Simple Neural Network in C#

2018-03-26