【C#】DLLを参照できない原因と今すぐ試せる解決策
参照できない主因はフレームワークやCPUアーキテクチャの不一致、DLLの配置ミス、ファイル属性のブロック、NuGetパッケージの未復元です。
Visual Studioでターゲットとプラットフォームを合わせ、Copy Local
を有効にし、dotnet restore
後に出力フォルダーへ再配置し、セキュリティブロックを解除すれば大抵解決できます。
よくある症状
C#でDLLを参照できない場合、どのような症状が現れるかを理解しておくことは問題解決の第一歩です。
ここでは、特に多く見られる代表的な症状を3つ紹介します。
コンパイル時の参照エラー
DLLを参照しようとした際に、Visual Studioやビルドツールがエラーを出すことがあります。
代表的なエラーメッセージには以下のようなものがあります。
- 「型または名前空間名 ‘XXX’ が見つかりませんでした」
- 「参照が見つかりません」
- 「アセンブリ ‘YYY.dll’ が見つかりません」
これらのエラーは、プロジェクトが指定したDLLを正しく認識できていないことを示しています。
原因としては、DLLの参照設定が間違っている、ターゲットフレームワークの不一致、DLLの配置場所が間違っているなどが考えられます。
例えば、プロジェクトの参照にDLLを追加していない場合や、DLLのパスが間違っている場合にこのエラーが発生します。
Visual Studioの「参照の追加」ダイアログでDLLを選択しても、ターゲットフレームワークが異なるとビルド時にエラーになることもあります。
この症状が出た場合は、まずプロジェクトの参照設定を見直し、DLLが正しい場所に存在しているか、ターゲットフレームワークが一致しているかを確認してください。
実行時のロード失敗
コンパイルは成功しても、プログラムの実行時にDLLのロードに失敗するケースもあります。
実行時エラーの代表例は以下の通りです。
FileNotFoundException
:「指定されたファイルが見つかりません」FileLoadException
:「ファイルの読み込みに失敗しました」BadImageFormatException
:「不正なイメージ形式です」
これらの例外は、実行時にCLR(共通言語ランタイム)がDLLを読み込めなかったことを示しています。
原因は多岐にわたりますが、主に以下のようなものがあります。
- DLLが実行ファイルの出力ディレクトリに存在しない
- CPUアーキテクチャの不一致(x86とx64の混在)
- 依存している別のDLLが不足している
- DLLがブロックされている(Windowsのセキュリティ機能による)
- strong name署名の不一致
例えば、x64環境でx86用のDLLを読み込もうとするとBadImageFormatException
が発生します。
また、DLLがダウンロードされたファイルである場合、Windowsがブロックしていることもあります。
実行時のロード失敗が起きた場合は、DLLの配置場所や依存関係、CPUアーキテクチャの整合性を確認し、必要に応じてDLLのブロック解除を行うことが重要です。
IntelliSenseに型が出ない
Visual StudioのIntelliSenseがDLLの型情報を認識できない場合もよくあります。
具体的には、以下のような状況です。
- 参照したDLLのクラスやメソッドが補完候補に表示されない
- 型名を入力してもエラーが表示される
- 名前空間が認識されず、usingディレクティブがエラーになる
この症状は、コンパイルエラーほど明確なエラーメッセージが出ないため、見落としやすいです。
原因としては、DLLの参照が正しく追加されていない、ターゲットフレームワークの不一致、またはVisual Studioのキャッシュが壊れていることが考えられます。
また、DLLが.NET Standardや.NET Core用で、プロジェクトが.NET Frameworkの場合など、互換性の問題でIntelliSenseが正しく動作しないこともあります。
IntelliSenseに型が出ない場合は、まずプロジェクトの参照設定を再確認し、Visual Studioを再起動したり、bin
やobj
フォルダをクリーンしてみることをおすすめします。
さらに、ターゲットフレームワークの整合性をチェックすることも重要です。
原因別チェックリスト
ターゲットフレームワークの不一致
.NET Frameworkと.NET Coreの相互参照制限
.NET Framework用に作成されたDLLは、基本的に.NET Coreや.NET 5/6/7などの新しいランタイムで直接参照できない場合があります。
逆も同様で、.NET Core用のDLLを.NET Frameworkプロジェクトに追加するとエラーになることが多いです。
これは、両者のランタイムやAPI仕様が異なるためです。
例えば、.NET Framework 4.7.2のプロジェクトに.NET Core 3.1用のDLLを参照しようとすると、ビルド時に「型が見つかりません」や「参照エラー」が発生します。
これを回避するには、両方の環境で共通して使える.NET StandardをターゲットにしたDLLを利用するか、プロジェクトのターゲットフレームワークを合わせる必要があります。
マイナーバージョン差異による型解決失敗
同じ.NET Frameworkや.NET Coreでも、マイナーバージョンの違いで型解決に失敗することがあります。
例えば、.NET Framework 4.6.1用のDLLを4.7.2のプロジェクトに参照すると問題ない場合もありますが、逆に4.7.2用のDLLを4.6.1のプロジェクトに追加するとエラーになることがあります。
このような場合は、プロジェクトのターゲットフレームワークをDLLのターゲットに合わせるか、DLLを再ビルドしてターゲットフレームワークを調整することが必要です。
CPUアーキテクチャのミスマッチ
x86/x64/AnyCPUの設定確認
DLLのCPUアーキテクチャとプロジェクトのビルド設定が一致していないと、実行時にBadImageFormatException
が発生します。
例えば、x64環境でx86用のDLLを読み込もうとするとエラーになります。
Visual Studioのプロジェクトプロパティで「プラットフォームターゲット」を確認し、DLLのビルド設定と合わせてください。
AnyCPU設定のDLLはどちらの環境でも動作しますが、ネイティブコードを含むDLLは特に注意が必要です。
ネイティブ依存ライブラリとの食い違い
マネージDLLがネイティブDLLに依存している場合、ネイティブDLLのアーキテクチャが合っていないとロードに失敗します。
例えば、x64のマネージDLLがx86のネイティブDLLを呼び出すとエラーになります。
この場合は、ネイティブDLLもプロジェクトのターゲットアーキテクチャに合わせて用意し、正しい場所に配置してください。
DLL配置の問題
参照パスの設定ミス
プロジェクトにDLLを参照追加しても、参照パスが正しく設定されていないとビルド時にDLLが見つかりません。
Visual Studioの参照プロパティでHintPath
が正しいか確認してください。
特に、相対パスで指定している場合は、プロジェクトのフォルダ構成が変わるとパスがずれてしまうことがあります。
絶対パスやNuGetパッケージを利用する方法も検討しましょう。
出力ディレクトリへのコピー漏れ
ビルド後にDLLが出力ディレクトリ(通常はbin\Debug
やbin\Release
)にコピーされていないと、実行時にロード失敗します。
参照のプロパティで「ローカルコピー」をTrue
に設定するか、ビルドイベントで手動コピーを行う方法があります。
セキュリティブロック
ダウンロードファイルのブロック解除
インターネットからダウンロードしたDLLはWindowsのセキュリティ機能でブロックされていることがあります。
この場合、実行時にロードが拒否されることがあります。
DLLのプロパティを開き、「ブロックの解除」ボタンを押すか、PowerShellで解除することが可能です。
Zone.Identifierの削除手順
ダウンロードファイルにはZone.Identifierという代替データストリームが付与されており、これがブロックの原因です。
以下のPowerShellコマンドで削除できます。
Unblock-File -Path "C:\path\to\your.dll"
これにより、Windowsのブロックが解除され、DLLが正常にロードされるようになります。
strong name署名の欠落
署名必須アセンブリのロード失敗
strong name署名が必要な環境で署名されていないDLLを読み込もうとすると、FileLoadException
が発生します。
特にGAC(グローバルアセンブリキャッシュ)に登録するDLLは署名が必須です。
sn.exeによる再署名
署名がないDLLを署名するには、Microsoftのsn.exe
ツールを使います。
以下のコマンドでキーを生成し、DLLに署名できます。
sn -k MyKey.snk
sn -R YourAssembly.dll MyKey.snk
ただし、再署名は元のDLLの整合性を壊す可能性があるため、元のソースから署名付きでビルドし直すのが望ましいです。
依存DLL不足
Dependency Walker/lddでの解析
DLLが他のDLLに依存している場合、依存先が不足するとロードに失敗します。
WindowsではDependency Walker
、Linuxではldd
コマンドで依存関係を調べられます。
これらのツールで依存DLLがすべて揃っているか確認し、不足しているDLLをプロジェクトに追加してください。
Fusionログビューアでの詳細確認
.NETのアセンブリバインディングの問題は、Fusionログビューアfuslogvw.exe
で詳細ログを取得できます。
ログを有効にして実行すると、どのDLLのロードに失敗したか、どのパスを探したかがわかります。
バージョン競合
BindingRedirectの設定
複数のDLLが異なるバージョンの同じアセンブリを参照している場合、バージョン競合が発生します。
app.config
やweb.config
にbindingRedirect
を設定して、特定のバージョンに統一することで解決します。
<dependentAssembly>
<assemblyIdentity name="ExampleAssembly" publicKeyToken="32ab4ba45e0a69a1" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
</dependentAssembly>
AssemblyVersionとAssemblyFileVersionの違い
AssemblyVersion
はCLRが参照解決に使うバージョンで、AssemblyFileVersion
はファイルのバージョン情報です。
AssemblyVersion
が変わると参照エラーになることがあるため、バージョン管理には注意が必要です。
NuGetパッケージ復元失敗
dotnet restoreエラー対処
NuGetパッケージが復元されていないと、依存DLLが不足して参照エラーになります。
コマンドラインでdotnet restore
を実行し、エラーが出た場合はエラーメッセージを確認してください。
ネットワーク障害やパッケージソースの設定ミスが多い原因です。
パッケージソースとプロキシ設定
企業ネットワークなどでプロキシを使っている場合、NuGetのパッケージソースにアクセスできないことがあります。
nuget.config
でプロキシ設定を追加したり、パッケージソースを変更して対応してください。
ファイルロックとキャッシュ
古いDLLのロック解除
ビルドや実行中にDLLがロックされていると、更新や削除ができず、古いDLLが使われ続けることがあります。
Visual Studioを再起動したり、プロセスを終了してロックを解除してください。
Cleanビルドとbin/obj削除
bin
やobj
フォルダに古いDLLが残っていると、ビルド時に正しいDLLが反映されません。
Visual Studioの「クリーン」機能を使うか、手動でこれらのフォルダを削除してから再ビルドしてください。
解決フロー
Visual Studioでの参照追加
プロジェクト参照とファイル参照の違い
Visual StudioでDLLを参照に追加する方法には大きく分けて「プロジェクト参照」と「ファイル参照」の2種類があります。
どちらを使うかで管理やビルドの挙動が変わるため、状況に応じて使い分けることが重要です。
プロジェクト参照は、同じソリューション内の別プロジェクトを参照する方法です。
Visual Studioの「参照の追加」ダイアログで「プロジェクト」タブから追加します。
これにより、依存関係が明示的になり、ビルド順序も自動で管理されます。
プロジェクトのビルド設定やターゲットフレームワークの不整合も検出しやすくなります。
一方、ファイル参照は、ビルド済みのDLLファイルを直接指定して参照に追加する方法です。
ソリューション外のDLLや外部ライブラリを使う場合に利用します。
ただし、DLLのパスが固定されるため、プロジェクトの移動や共有時にパスが壊れやすい点に注意が必要です。
また、ファイル参照の場合は、DLLの更新があっても自動的にビルドされないため、手動でDLLを差し替える必要があります。
プロジェクト参照はソースコードの変更に追従するため、開発効率が高いです。
HintPathの編集ポイント
ファイル参照で追加したDLLは、プロジェクトファイル.csproj
内にHintPath
という要素でパスが記述されています。
このパスが正しく設定されていないと、ビルド時にDLLが見つからずエラーになります。
HintPath
は相対パスで指定されることが多いですが、プロジェクトのフォルダ構成が変わるとパスがずれてしまうことがあります。
Visual Studioの参照プロパティからパスを修正するか、直接.csproj
ファイルをテキストエディタで開いて編集してください。
例えば、以下のように記述されています。
<Reference Include="MyLibrary">
<HintPath>..\libs\MyLibrary.dll</HintPath>
</Reference>
この場合、..\libs\MyLibrary.dll
が実際に存在するかを確認し、存在しなければ正しいパスに修正します。
パスの指定ミスは参照エラーの原因として非常に多いので、必ずチェックしてください。
CLIでの参照追加
dotnet add referenceの使い方
.NET Coreや.NET 5以降のSDKスタイルプロジェクトでは、コマンドラインから参照を追加することができます。
dotnet add reference
コマンドを使うと、プロジェクト参照を簡単に追加できます。
使い方は以下の通りです。
dotnet add <プロジェクトファイル> reference <参照先プロジェクトファイル>
例えば、MyApp.csproj
にMyLibrary.csproj
を参照追加する場合は、
dotnet add MyApp.csproj reference ../MyLibrary/MyLibrary.csproj
と実行します。
これにより、MyApp.csproj
のItemGroup
にプロジェクト参照が追加され、ビルド時に依存関係が自動で解決されます。
DLLファイルを直接参照する場合はdotnet add package
でNuGetパッケージを追加するか、csproj
を直接編集する必要があります。
SDKスタイルプロジェクトのItemGroup
SDKスタイルのプロジェクトファイルはXML形式で、ItemGroup
要素内に参照情報が記述されています。
プロジェクト参照は以下のように記述されます。
<ItemGroup>
<ProjectReference Include="..\MyLibrary\MyLibrary.csproj" />
</ItemGroup>
ファイル参照の場合は、Reference
要素とHintPath
を使います。
<ItemGroup>
<Reference Include="MyLibrary">
<HintPath>..\libs\MyLibrary.dll</HintPath>
</Reference>
</ItemGroup>
このように、ItemGroup
内の記述を直接編集することで、細かい参照設定が可能です。
Visual Studioでの操作と連動しているため、手動編集後はIDEを再起動すると反映されやすくなります。
設定変更後のビルド確認
再起動が必要なケース
参照設定を変更した後、Visual Studioやビルドツールが古い情報をキャッシュしている場合があります。
特にHintPath
を手動で編集したり、DLLの配置を変更した場合は、IDEの再起動が必要になることがあります。
再起動しないと、IntelliSenseが更新されなかったり、ビルドエラーが解消されないことがあるため、設定変更後は一度Visual Studioを閉じて再度開くことをおすすめします。
また、ビルドキャッシュの影響で古いDLLが使われることもあるため、クリーンビルドを行うことも効果的です。
バージョン情報のダブルチェック
参照しているDLLのバージョンが正しいかどうかも必ず確認してください。
特に複数バージョンのDLLが混在している環境では、誤ったバージョンを参照していることが原因でエラーが発生します。
Visual Studioの「参照」タブや、Properties
ウィンドウでDLLのバージョン情報を確認できます。
また、AssemblyVersion
とFileVersion
の違いにも注意してください。
AssemblyVersion
はCLRが参照解決に使うため、こちらが一致していることが重要です。
バージョンが合っていない場合は、正しいDLLを参照に追加し直すか、bindingRedirect
を設定してバージョンの不整合を解消してください。
トラブル診断ツール
ILSpyでのメタデータ確認
ILSpyはオープンソースの.NETアセンブリデコンパイラで、DLLの中身を解析するのに便利なツールです。
DLLのメタデータや型情報、依存関係を視覚的に確認できるため、参照できない原因を特定する際に役立ちます。
ILSpyでDLLを開くと、名前空間やクラス、メソッドの一覧が表示されます。
これにより、DLLが正しくビルドされているか、目的の型が含まれているかを確認できます。
また、参照している他のアセンブリも一覧で見られるため、依存関係の不足をチェックできます。
例えば、DLLに期待したクラスが存在しない場合は、ビルドミスやターゲットフレームワークの不一致が疑われます。
ILSpyは無料で使えるので、まずはDLLの中身を確認する際に活用してください。
Assembly Binding Log Viewer
Assembly Binding Log Viewerfuslogvw.exe
は、.NETのアセンブリバインディングの詳細ログを取得できるツールです。
DLLのロードに失敗した場合、どのパスを探したか、どのバージョンを要求したかなどの情報をログで確認できます。
使い方は、管理者権限でfuslogvw.exe
を起動し、「Log bind failures to disk」を有効にします。
その後、問題のアプリケーションを実行すると、ログが記録されます。
ログには、ロードに成功したアセンブリと失敗したアセンブリの詳細が含まれ、原因特定に非常に役立ちます。
ログの内容から、DLLのパスが間違っている、バージョンが合っていない、依存DLLが不足しているなどの問題を見つけられます。
問題解決後はログを無効にしておくことを忘れないでください。
Process Monitorによるファイルアクセス解析
Process Monitor(ProcMon)は、Windowsのファイルシステムやレジストリのアクセスをリアルタイムで監視できる強力なツールです。
DLLのロード失敗時に、どのファイルパスを探しているか、アクセスが拒否されているかを詳細に調べられます。
ProcMonを起動し、対象のプロセスをフィルタリングして監視します。
DLLのファイル名やパスでフィルタをかけると、どのフォルダを検索しているか、ファイルが存在しない、アクセス権限がないなどの状況がわかります。
例えば、DLLが存在しないパスを探している場合は、参照パスの設定ミスが疑われます。
アクセス拒否があれば、ファイルの権限設定やセキュリティソフトの影響を確認してください。
msbuildの詳細ログ取得
msbuildはVisual Studioのビルドエンジンで、詳細なビルドログを取得することで、DLL参照に関する問題を深掘りできます。
通常のビルドログでは見えない参照解決の過程やエラーの詳細がわかります。
コマンドラインで以下のように実行すると、詳細ログをファイルに出力できます。
msbuild YourProject.csproj /v:diag > build.log
/v:diag
は詳細(diagnostic)レベルのログを意味し、参照解決の手順や失敗の原因が細かく記録されます。
ログファイルをテキストエディタで開き、error
やwarning
を検索して問題箇所を特定してください。
Visual Studioのビルド出力ウィンドウでも詳細ログを表示できますが、ファイルに保存してじっくり解析するほうが効率的です。
ビルドの問題が複雑な場合は、この方法で原因を追いかけることをおすすめします。
コードサンプル集
ロード失敗時の例外ハンドリング
DLLのロードに失敗した場合、例外が発生します。
これを適切にキャッチして原因を特定しやすくするための例外ハンドリングのサンプルです。
Assembly.LoadFrom
を使ってDLLをロードし、失敗時に詳細な情報を取得します。
using System;
using System.Reflection;
class Program
{
static void Main()
{
string dllPath = @"C:\libs\MyLibrary.dll"; // 読み込むDLLのパス
try
{
// DLLをロードする
Assembly assembly = Assembly.LoadFrom(dllPath);
Console.WriteLine("DLLのロードに成功しました。");
}
catch (System.IO.FileNotFoundException ex)
{
Console.WriteLine("DLLが見つかりませんでした。パスを確認してください。");
Console.WriteLine($"詳細: {ex.Message}");
}
catch (BadImageFormatException ex)
{
Console.WriteLine("DLLの形式が不正です。CPUアーキテクチャの不一致が疑われます。");
Console.WriteLine($"詳細: {ex.Message}");
}
catch (FileLoadException ex)
{
Console.WriteLine("DLLの読み込みに失敗しました。依存関係やセキュリティ設定を確認してください。");
Console.WriteLine($"詳細: {ex.Message}");
}
catch (Exception ex)
{
Console.WriteLine("予期しないエラーが発生しました。");
Console.WriteLine($"詳細: {ex.Message}");
}
}
}
DLLのロードに成功しました。
このコードは、DLLのパスが間違っている場合やCPUアーキテクチャの不一致、依存DLL不足などで発生しやすい例外を個別にキャッチしています。
これにより、問題の切り分けがしやすくなります。
リフレクションによるDLL存在チェック
DLLが存在するかどうかを事前にチェックし、存在しなければ処理を中断するサンプルです。
ファイルの存在確認と、存在した場合はリフレクションで簡単な型情報を取得してみます。
using System;
using System.IO;
using System.Reflection;
class Program
{
static void Main()
{
string dllPath = @"C:\libs\MyLibrary.dll";
if (!File.Exists(dllPath))
{
Console.WriteLine("指定したDLLが存在しません。パスを確認してください。");
return;
}
try
{
Assembly assembly = Assembly.LoadFrom(dllPath);
Console.WriteLine("DLLのロードに成功しました。");
// 最初の名前空間と型名を取得して表示
Type[] types = assembly.GetTypes();
if (types.Length > 0)
{
Console.WriteLine($"最初の型名: {types[0].FullName}");
}
else
{
Console.WriteLine("DLLに型が含まれていません。");
}
}
catch (Exception ex)
{
Console.WriteLine("DLLのロード中にエラーが発生しました。");
Console.WriteLine($"詳細: {ex.Message}");
}
}
}
DLLのロードに成功しました。
最初の型名: MyLibrary.SampleClass
このコードは、DLLの存在をファイルシステムで確認し、存在すればリフレクションで型情報を取得します。
存在しない場合は早期に処理を中断できるため、無駄な例外発生を防げます。
AssemblyLoadContextでの動的ロード
.NET Core以降で利用可能なAssemblyLoadContext
を使い、DLLを動的にロードしてアンロード可能にするサンプルです。
これにより、プラグインのようにDLLを動的に読み込み、必要なくなったらメモリから解放できます。
using System;
using System.Reflection;
using System.Runtime.Loader;
class PluginLoadContext : AssemblyLoadContext
{
private AssemblyDependencyResolver _resolver;
public PluginLoadContext(string pluginPath) : base(isCollectible: true)
{
_resolver = new AssemblyDependencyResolver(pluginPath);
}
protected override Assembly Load(AssemblyName assemblyName)
{
string assemblyPath = _resolver.ResolveAssemblyToPath(assemblyName);
if (assemblyPath != null)
{
return LoadFromAssemblyPath(assemblyPath);
}
return null;
}
}
class Program
{
static void Main()
{
string pluginPath = @"C:\plugins\MyPlugin.dll";
var loadContext = new PluginLoadContext(pluginPath);
try
{
Assembly pluginAssembly = loadContext.LoadFromAssemblyPath(pluginPath);
Console.WriteLine("プラグインDLLのロードに成功しました。");
// プラグイン内の型を取得してインスタンス化(例)
Type pluginType = pluginAssembly.GetType("MyPlugin.PluginClass");
if (pluginType != null)
{
object pluginInstance = Activator.CreateInstance(pluginType);
Console.WriteLine($"プラグインの型 {pluginType.FullName} をインスタンス化しました。");
}
else
{
Console.WriteLine("指定した型がプラグインに存在しません。");
}
}
catch (Exception ex)
{
Console.WriteLine("プラグインのロード中にエラーが発生しました。");
Console.WriteLine($"詳細: {ex.Message}");
}
finally
{
// アンロードを試みる
loadContext.Unload();
Console.WriteLine("プラグインのアンロードを試みました。");
}
}
}
プラグインDLLのロードに成功しました。
プラグインの型 MyPlugin.PluginClass をインスタンス化しました。
プラグインのアンロードを試みました。
AssemblyLoadContext
を使うことで、動的にDLLを読み込み、不要になったらアンロードできます。
これにより、メモリリークを防ぎつつプラグイン機能を実装できます。
AssemblyDependencyResolver
は依存DLLの解決も自動で行うため便利です。
GACに登録したのに参照できない場合
GAC(グローバルアセンブリキャッシュ)にDLLを登録しても、プロジェクトで参照できないケースがあります。
主な原因は以下の通りです。
- プロジェクトの参照設定がGACを参照していない
Visual Studioの参照設定で、GACに登録されたアセンブリを明示的に参照していない場合、ビルド時に見つからないことがあります。
GAC登録だけでは自動的に参照されないため、プロジェクトの参照に追加する必要があります。
- ターゲットフレームワークの不一致
GACに登録したDLLのターゲットフレームワークとプロジェクトのターゲットが異なると、参照エラーが発生します。
特に.NET Frameworkのバージョン違いに注意してください。
- 署名の不一致
GACに登録するにはstrong name署名が必要です。
署名が異なるDLLを参照しようとするとロードに失敗します。
- ビルド構成の問題
DebugビルドとReleaseビルドで参照設定が異なる場合があります。
両方の構成でGAC参照が正しく設定されているか確認してください。
GACに登録したDLLを使う場合は、Visual Studioの参照追加で「参照」ダイアログから「参照可能なアセンブリ」リストに表示されるか確認し、正しく追加してください。
Unity/XamarinでのDLL参照制限
UnityやXamarinなどの特定のプラットフォームでは、DLLの参照に制限があります。
主なポイントは以下の通りです。
- 対応する.NETランタイムの違い
UnityはMonoランタイムやIL2CPPを使い、XamarinはMonoベースのランタイムを使用します。
これらはフルの.NET Frameworkや.NET Coreとは異なるため、すべてのDLLが動作するわけではありません。
- プラットフォーム固有の制約
iOSやAndroid向けのXamarinでは、ネイティブコードを含むDLLや特定のAPIを使ったDLLは動作しません。
Unityも同様に、プラットフォームに依存したDLLは制限されます。
- DLLのビルド設定
Unityでは、.NET Standard 2.0や.NET Framework 3.5/4.xのDLLが推奨されます。
Xamarinも対応するターゲットフレームワークに合わせてDLLをビルドする必要があります。
- AOTコンパイルの影響
iOSなどのAOT(Ahead-Of-Time)コンパイル環境では、動的なリフレクションや動的ロードが制限されるため、DLLの使い方に注意が必要です。
これらの制限を踏まえ、UnityやXamarinでDLLを使う場合は、対応するランタイムやプラットフォームのドキュメントを参照し、互換性のあるDLLを用意してください。
リリースビルドのみで発生する不具合
開発中のDebugビルドでは問題なく動作するのに、ReleaseビルドでのみDLL参照に関する不具合が発生することがあります。
原因としては以下が考えられます。
- コード最適化による影響
Releaseビルドではコードの最適化が有効になり、不要と判断されたコードや変数が削除されることがあります。
これにより、リフレクションで参照している型が消えてしまい、実行時エラーになることがあります。
- 条件付きコンパイルやプリプロセッサディレクティブ
DebugとReleaseで異なるコードがコンパイルされている場合、Releaseで必要なDLL参照が除外されている可能性があります。
- DLLのコピー設定の違い
Releaseビルドの出力ディレクトリにDLLが正しくコピーされていない場合、実行時にロード失敗します。
プロジェクトの「ローカルコピー」設定を確認してください。
- 署名や暗号化の違い
Releaseビルドで署名や暗号化処理が追加されている場合、DLLのロードに影響を与えることがあります。
Releaseビルドで問題が起きたら、まずはコード最適化を無効にして動作を確認し、ビルド設定の差異を洗い出すことが重要です。
CI/CDパイプラインでの参照失敗対処
CI/CD環境でDLL参照が失敗する場合、ローカル環境とは異なる要因が絡んでいることが多いです。
対処法は以下の通りです。
- 依存DLLやNuGetパッケージの復元漏れ
パイプラインでdotnet restore
やnuget restore
が正しく実行されているか確認してください。
依存関係が解決されていないとビルドやテストで参照エラーになります。
- パスの違いと環境変数
ローカルとCI環境でフォルダ構成や環境変数が異なると、HintPath
や参照パスが正しく解決されません。
相対パスの見直しや環境変数の設定を行いましょう。
- ビルドエージェントのアーキテクチャ
x86/x64の違いやOSの違いでDLLのロードに失敗することがあります。
ビルドエージェントの環境を確認し、ターゲットと一致させてください。
- キャッシュの影響
古いDLLやパッケージのキャッシュが残っていると、最新のDLLが反映されません。
パイプラインでクリーンビルドを行うか、キャッシュクリアのステップを追加してください。
- 権限やセキュリティ設定
CI環境のユーザー権限やセキュリティポリシーでDLLの読み込みが制限される場合があります。
必要な権限を付与し、セキュリティ設定を確認してください。
CI/CDでの参照失敗は環境依存の問題が多いため、ログを詳細に確認し、環境差異を潰していくことが解決の近道です。
まとめ
この記事では、C#でDLLを参照できない際によく起こる症状や原因別のチェックポイント、具体的な解決フローを詳しく解説しました。
Visual StudioやCLIでの参照追加方法、トラブル診断に役立つツールの使い方、コードサンプルによる例外処理や動的ロードの実装例も紹介しています。