Unity
ADF

【Unity】 Assembly Definition Files を使った上でinternalにアクセスする方法


今回の話の内容を2行で

Assembly Definition Filesを使ってdllを分けると、テストのときにiternalなアクセスレベルの要素にアクセスができずに困る。

対策として、AssmeblyInfo.csを書こうという話。


AssemblyInfo.cs

using System.Runtime.CompilerServices;

// 指定したdllから、internalアクセスレベルへのアクセスを許可する
[assembly: InternalsVisibleTo("MyLibrary.Test")] //adfで定義した名前と一致させる



本題


Assembly Definition Files

Unityには、Assembly Definition Files(以下adf)という機能があります。

これはadfファイルが置かれたディレクトリのスクリプトを別のdllに分けてコンパイルするという機能です。

adfファイルを使うことで、プロジェクト本体とは独立性が高い部分を別のライブラリに切り出して依存関係を管理するなど、プロジェクト構成の管理に使うことができます。

詳しくはテラシュールブログさんのこの記事を参考にしてください。


C#のinternalアクセシビリティ

話が変わって、C#にはiternalというアクセスレベルが用意されています。

これは「同一のプロジェクト内(同一dll内)からのみアクセス可能にする」というアクセスレベルです。


Assembly Definition Filesとinternalを組み合わせる

adfinternalを組み合わせることで、ライブラリが提供するオブジェクトの利用方法を制限することができます。

(ライブラリ内では制約なしで自由にメソッドコールできるが、ユーザからは一部のメソッドしか利用できないなど)


使用例:コンストラクタをinternalにする

たとえば、こんなクライアントがあったとします。

using System;

namespace MyLibrary
{
/// <summary>
/// 何かのクライアントがあって
/// </summary>
public class HogeClient
{
private string _token;

/// <summary>
/// インスタンス化にはTokenが必要なのだが、
/// このTokenを使ったコンストラクタはライブラリ外に露出させたくないので internal
/// </summary>
/// <param name="token"></param>
internal HogeClient(string token)
{
_token = token;
}
}

/// <summary>
/// Clientのファクトリー
/// </summary>
public class HogeClientFactory
{
/// <summary>
/// Clientの生成時に、Tokenを取得して埋め込む
/// 不正なTokenを埋め込んだ状態でClientは生成できない
/// </summary>
public HogeClient CreateClient()
{
var token = FetchToken();
if (!ValidationToken(token)) throw new Exception("Invalid token.");

return new HogeClient(token);
}

private string FetchToken()
{
/**
* ScriptableObjectとか、サーバとか、何らかの方法で
* Tokenを取得する想定
*/

return "sample_token";
}

private bool ValidationToken(string token)
{
/**
* Tokenの有効性を確認したりとか?
*/

return true;
}
}
}

ここに、次のようなadfファイルを定義し、HogeClientを別のdllとして分離します。

image.png

こうすることで、HogeClientのコンストラクタは外部からアクセス不可になり、必ずファクトリ経由でのインスタンス化をユーザに強制することができるようになります。

image.png


問題点:テストの時どうするの?

adfinternalを組み合わせることで、ライブラリの使用方法を制限することができるようになりました。

が、ライブラリのテストを書きたいときはこの制限は非常に邪魔になります。


例:さっきのクライアントのテストを書きたい

テスト用のadfが切られていたとして。

image.png

この状態でテストを書くと、internalにやはりアクセスできないのでHogeClientが初期化できない。

image.png


解決策:AssemblyInfo.csを配置する

解決策として、adfファイルが置かれている階層にAssemblyInfo.csを配置して次のコードを書くことで対処できます。


AssemblyInfo.cs

using System.Runtime.CompilerServices;

// MyLibrary.Testプロジェクトに対してはinternalアクセスを許可する
[assembly: InternalsVisibleTo("MyLibrary.Test")] //adfで定義した名前と一致させる


image.png

AssemblyInfo.cs内にInternalsVisibleToを書くことで、特定のプロジェクト(dll)に対してのみinternalアクセスを許可することができます。

これでテスト用ライブラリに対して許可をしてあげることで、テスト時にinternalアクセスが可能になります。

image.png