CSharp のプロジェクトを dotnet で
この記事に関連するお話です。
dotnet で C# のパッケージ作成をしてみます。手元にあるものが 1.0 系なので古いけど、雰囲気を味わうことはできるでしょう。
雛形の作成
雛形のディレクトリは作成してくれないので、あらかじめ作業ディレクトリを作成しておき、その中でコマンドを入力します。
mkdir csmto cd csmto dotnet new console
作成されるのは Program.cs
と csmto.csproj
。バージョンが古いので、dotnet restore
を実行しておく必要があります。こうすると project.assets.json
等を生成してくれるのです。
プロジェクトの設定
今のところ特に設定すべきものはありません。
プロジェクトの実装
mono とは異なっているので、実装の変更をすることになりました。次の部分で苦労してしまいました。
foreach statement cannot operate on variables of type 'csmto.Program.ArrayList' because 'csmto.Program.ArrayList' does not contain a public definition for 'GetEnumerator' [csmto]
Program.cs(85,38): error CS1579: foreach statement cannot operate on variables of type 'csmto.Program.ArrayList' because 'csmto.Program.ArrayList' does not contain a public definition for 'GetEnumerator' [/Users/home/csmto/csmto.csproj] The build failed. Please fix the build errors and run again.
調べてみると、dotnet core だと気楽にリストを foreach できないみたい。ArrayList 自体が古い規格のものらしく、最近は List を使うらしいです。そこで ArrayList を List<List
次のようにして実行することができます。--
で引数を run に渡せます。後者の方が速いです。
dotnet run -- tradkana Hidoi.txt dotnet bin/Debug/netcoreapp1.1/csmto.dll tradkana Hidoi.txt
テストの記述
今のままではダメみたいなので、次のようにしてディレクトリ構成を変更しました。
- CsMto ディレクトリを作成してファイルを移動 (名前も csmto -> CsMto へ)。
dotnet new sln
を実行。csmto.sln
ファイルが作成される。dotnet sln add CsMto/CsMto.csproj
を実行して sln に追加。mkdir CsMto.Tests
でテスト用のディレクトリを作成し、その中に入ってdotnet new xunit
を実行してテストを作成。CsMto/test はこちらに移動。- UnitTest1.cs と CsMto.Tests.csproj ファイルが作成されている。この CsMto.Tests.csproj に CsMto を認識させるために
dotnet add reference ../CsMto/CsMto.csproj
を実行。 - さらに上の階層に移動して
dotnet sln add CsMto.Tests/CsMto.Tests.csproj
で sln に追加。 - とりあえず
dotnet restore
を実行しておく。
csmto 内で dotnet build
を実行すると、次のようにアプリとテストの両方をビルドしてくれました。
> dotnet build Microsoft (R) Build Engine version 15.1.1012.6693 Copyright (C) Microsoft Corporation. All rights reserved. CsMto -> /Users/home/csmto/CsMto/bin/Debug/netcoreapp1.1/CsMto.dll CsMto.Tests -> /Users/home/csmto/CsMto.Tests/bin/Debug/netcoreapp1.1/CsMto.Tests.dll Build succeeded. 0 Warning(s) 0 Error(s) Time Elapsed 00:00:03.27
dotnet test
を実行すると下記のエラーに。
Couldn't find a project to run test from. Ensure a project exists in /Users/home/csmto. Or pass the path to the project
CsMto.Tests に移動して dotnet test
を実行するとうまくいきました。
> dotnet test Build started, please wait... Build completed. Test run for /Users/home/csmto/CsMto.Tests/bin/Debug/netcoreapp1.1/CsMto.Tests.dll(.NETCoreApp,Version=v1.1) Microsoft (R) Test Execution Command Line Tool Version 15.0.0.0 Copyright (c) Microsoft Corporation. All rights reserved. テスト実行を開始しています。お待ちください... [xUnit.net 00:00:00.7561953] Discovering: CsMto.Tests [xUnit.net 00:00:00.9055221] Discovered: CsMto.Tests [xUnit.net 00:00:00.9710108] Starting: CsMto.Tests [xUnit.net 00:00:01.1647042] Finished: CsMto.Tests テストの合計数: 1。成功: 1。失敗:0。スキップ: 0。 テストの実行に成功しました。 テスト実行時間: 2.1563 秒
あとはテストを実装していくだけ。と気楽に考えていたら、別のクラス (CsMto) のメソッドが実行できないのでした。Mto.cs 内で辞書作成部分、文字列置換部分を MtoLib というクラスに分け、引数処理の部分は Program クラスのままにしました。
UnitTest.cs からは CsMto.MtoLib.CreateDictionary() でアクセスすることができるようになりました。ReplaceTextInFileCar 等は Console.Write で出力しているのをやめて、void 型から string 型に変更し、変換した文字列を返す関数としました。これでテスト側で受け取ることができるようになり、比較が可能となりました。
内部辞書の比較部分で苦労することに。結局下記のようにすれば作成できることがわかりました。
List<List<string>> validdic = new List<List<string>>() { new List<string>() {"こんにちは", "こんにちわ"}, new List<string>() {"こんばんは", "こんばんわ"}, new List<string>() {"たなこふ", "(´・_・`)"}, new List<string>() {"くどう", "せやかて"}, new List<string>() {"高鴎福吉", "髙鷗福𠮷"}, new List<string>() {"葛", "葛󠄀"}, new List<string>() {"ヒラギノ角ゴ", "ヒラギノ角ゴ"}, new List<string>() {"김", "김"}, new List<string>() {"🍣", "🍻"}, new List<string>() {"ありがとう", "おおきに"} };
いちいちテストディレクトリに移動しなければなりません。ソリューションディレクトリ内でテストを実行するには、次のようにプロジェクトディレクトリの .csporj
を指定してやればいいのでした。
dotnet test CsMto.Tests/CsMto.Tests.csproj
実行する時も同様で --project オプションで渡します。
dotnet run --project CsMto/CsMto.csproj
パッケージの作成
nuget pack -c Release
を実行すると CsMto/bin/Release/CsMto.1.0.0.nupkg が作成されます。テストは警告が出るものの、CsMto.Tests/bin/Release/CsMto.Tests.1.0.0.nupkg は作成されました。これらを nuget.org 等で配布することになるのですが、GitHub などから Git リポジトリとして直接配布することはできないみたいです。
GitHub からのインストール
無理っぽい。