前回は、.NET アプリケーションの設定ファイルについて見ました。
今回は、クラスライブラリを作成し、別のアプリケーションから参照して使う流れを確認します。
あわせて、アセンブリのマニフェスト、型メタデータ、internal 型の公開範囲も見ていきます。
クラスライブラリを作成する
まず、再利用したい処理をクラスライブラリとして作ります。
dotnet new classlib -n TextTools
次のようなクラスを用意します。
namespace TextTools;
public static class TextFormatter
{
public static string Bracket(string value)
{
return $"[{value}]";
}
public static string Quote(string value)
{
return $"\"{value}\"";
}
}
public にした型やメンバーは、他のアセンブリから参照できます。
コンソールアプリから利用する
次に、ライブラリを利用するコンソールアプリを作ります。
dotnet new console -n TextClient
プロジェクト参照を追加します。
dotnet add TextClient/TextClient.csproj reference TextTools/TextTools.csproj
コンソールアプリ側で呼び出します。
using TextTools;
string text = TextFormatter.Bracket("hello");
Console.WriteLine(text);
実行すると、ライブラリ内の処理を利用できます。
dotnet run --project TextClient
プロジェクト参照を使うと、ビルド時に依存関係が解決され、必要な DLL が出力先へコピーされます。
アセンブリ情報を確認する
参照しているライブラリのアセンブリ情報は、リフレクションで確認できます。
using System.Reflection;
using TextTools;
Assembly assembly = typeof(TextFormatter).Assembly;
AssemblyName name = assembly.GetName();
Console.WriteLine($"名前: {name.Name}");
Console.WriteLine($"バージョン: {name.Version}");
Console.WriteLine($"場所: {assembly.Location}");
Console.WriteLine($"完全名: {assembly.FullName}");
typeof(TextFormatter).Assembly により、TextFormatter 型が定義されているアセンブリを取得できます。
参照アセンブリを確認する
アセンブリが参照している別のアセンブリも取得できます。
using System.Reflection;
using TextTools;
Assembly assembly = typeof(TextFormatter).Assembly;
foreach (AssemblyName referenced in assembly.GetReferencedAssemblies())
{
Console.WriteLine(referenced.FullName);
}
これにより、ライブラリがどのアセンブリに依存しているかを確認できます。
型メタデータを確認する
アセンブリ内に含まれる型も列挙できます。
using System.Reflection;
using TextTools;
Assembly assembly = typeof(TextFormatter).Assembly;
foreach (Type type in assembly.GetTypes())
{
Console.WriteLine(type.FullName);
foreach (MethodInfo method in type.GetMethods(
BindingFlags.Public |
BindingFlags.Static |
BindingFlags.Instance |
BindingFlags.DeclaredOnly))
{
Console.WriteLine($" {method.ReturnType.Name} {method.Name}");
}
}
このような型情報は、DI コンテナー、テストフレームワーク、シリアライザー、プラグイン探索などで活用されます。
中間言語を確認する考え方
C# のコードは、ビルド時に中間言語へ変換されます。
通常のアプリ開発で中間言語を直接読む必要はありませんが、次のような流れを知っておくと .NET の実行モデルを理解しやすくなります。
C# コード
↓
中間言語とメタデータ
↓
実行時に JIT コンパイル
↓
CPU が実行するネイティブコード
SDK だけで中間言語をきれいに表示する標準コマンドは限定的ですが、ILSpy などの逆コンパイルツールを使うと、ビルド後の DLL から中間言語や C# 風のコードを確認できます。
別言語から同じライブラリを使う
.NET アセンブリは、C# 以外の .NET 言語からも利用できます。
たとえば、Visual Basic のプロジェクトから C# で作ったクラスライブラリを参照できます。
C# 側です。
namespace SharedModels;
public class Person
{
public string Name { get; set; } = "";
public string Greet()
{
return $"Hello, {Name}";
}
}
Visual Basic 側では、同じアセンブリを参照して次のように利用できます。
Imports SharedModels
Module Program
Sub Main()
Dim person As New Person()
person.Name = "Alice"
Console.WriteLine(person.Greet())
End Sub
End Module
.NET では、共通の中間言語とメタデータがあるため、複数言語間で型を共有できます。
internal 型を別アセンブリへ公開する
internal は、同じアセンブリ内からだけアクセスできる可視性です。
namespace TextTools;
internal class TextNormalizer
{
public string Normalize(string value)
{
return value.Trim().ToUpperInvariant();
}
}
通常、別のアセンブリから TextNormalizer は見えません。
ただし、テストプロジェクトなど特定のアセンブリにだけ内部型を見せたい場合は、InternalsVisibleTo を使えます。
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("TextTools.Tests")]
この属性をライブラリ側に追加すると、TextTools.Tests アセンブリから internal 型やメンバーへアクセスできます。
使いどころとしては、単体テストで内部実装を検証したい場合が代表的です。
ただし、内部実装に強く依存したテストが増えすぎると設計変更が難しくなるため、公開 API のテストとのバランスが大切です。
まとめ
クラスライブラリは、再利用したい処理をまとめるための基本単位です。
コンソールアプリや Web アプリからプロジェクト参照を追加すれば、ライブラリ内の public 型を利用できます。
また、アセンブリにはマニフェストや型メタデータが含まれており、リフレクションで情報を調べられます。
次回は、作成したライブラリを NuGet パッケージとして扱う方法と、アプリケーションを発行する流れを見ていきます。