bucket-sort logo bucket-sort

プログラミングとインフラエンジニアリングの覚え書き

  • Posts
  • About
  • Contact
  1. Home
  2. All Posts
  3. [C#] 外部アセンブリを読み込み実行時に型を呼び出す

[C#] 外部アセンブリを読み込み実行時に型を呼び出す

Jul 7, 2026 C# , .NET bucket-sort

前回は、リフレクションで型の中身を調べる方法を見ました。

今回は一歩進んで、外部アセンブリを実行時に読み込み、型を探し、インスタンスを作り、メソッドを呼び出します。
この考え方は、プラグイン機構や拡張機能を作るときの基本になります。

実行時に読み込むとはどういうことか

通常の C# アプリケーションでは、参照するライブラリはビルド時に決まっています。

<ProjectReference Include="..\MyLibrary\MyLibrary.csproj" />

一方、拡張可能なアプリケーションでは、あとから追加された DLL を実行時に読み込みたいことがあります。

たとえば、次のような構成です。

App/
  ExtensibleApp.exe
  Plugins/
    CsvImporter.dll
    JsonImporter.dll

アプリ本体は、起動時に Plugins フォルダーを調べ、そこにある DLL を読み込みます。
これにより、アプリ本体を再ビルドしなくても機能を追加できます。

外部アセンブリを読み込む

もっとも単純には、Assembly.LoadFrom() で DLL を読み込めます。

using System.Reflection;

string pluginPath = @"C:\Plugins\SamplePlugin.dll";

Assembly assembly = Assembly.LoadFrom(pluginPath);

Console.WriteLine(assembly.FullName);

現代の .NET でプラグインを本格的に扱うなら、依存関係やアンロードを考えて AssemblyLoadContext を使う方が柔軟です。
ただし、まず仕組みを理解する入口としては Assembly.LoadFrom() でも十分です。

型を探す

読み込んだアセンブリから型を列挙できます。

using System.Reflection;

Assembly assembly = Assembly.LoadFrom(@"C:\Plugins\SamplePlugin.dll");

foreach (Type type in assembly.GetTypes())
{
    Console.WriteLine(type.FullName);
}

特定の名前の型を探すなら、次のようにします。

Type? pluginType = assembly.GetTypes()
    .FirstOrDefault(type => type.Name == "SamplePlugin");

if (pluginType == null)
{
    Console.WriteLine("型が見つかりません。");
    return;
}

名前だけで探す方法は簡単ですが、壊れやすいです。
実務では、後で見るように共通インターフェイスや属性で探す方が安全です。

インスタンスを作成する

Activator.CreateInstance() を使うと、実行時に型からインスタンスを作れます。

object? instance = Activator.CreateInstance(pluginType);

if (instance == null)
{
    Console.WriteLine("インスタンスを作成できませんでした。");
    return;
}

引数ありのコンストラクターも呼び出せます。

object? instance = Activator.CreateInstance(
    pluginType,
    "Plugin Name",
    3);

ただし、引数の順番や型を間違えると実行時例外になります。
静的型付けの安全性は弱くなるため、境界を小さく保つことが大切です。

引数なしメソッドを呼び出す

MethodInfo.Invoke() を使うと、実行時にメソッドを呼び出せます。

using System.Reflection;

MethodInfo? method = pluginType.GetMethod("Run");

if (method == null)
{
    Console.WriteLine("Run メソッドが見つかりません。");
    return;
}

method.Invoke(instance, parameters: null);

このコードは、コンパイル時には Run メソッドの存在を知りません。
実行時にメタデータを調べて呼び出しています。

引数ありメソッドを呼び出す

引数を渡す場合は、object?[] を使います。

MethodInfo? method = pluginType.GetMethod("Execute");

if (method == null)
{
    Console.WriteLine("Execute メソッドが見つかりません。");
    return;
}

object? result = method.Invoke(
    instance,
    new object?[] { "input.txt", 10 });

Console.WriteLine(result);

戻り値も object? として返ります。
必要に応じてキャストします。

if (result is string message)
{
    Console.WriteLine(message);
}

共通インターフェイスで安全に呼び出す

遅延バインディングは柔軟ですが、文字列ベースの呼び出しは壊れやすいです。
拡張可能なアプリでは、共通インターフェイスを用意する設計が扱いやすくなります。

namespace PluginContracts;

public interface IPlugin
{
    string Name { get; }
    void Execute();
}

プラグイン側です。

using PluginContracts;

public class HelloPlugin : IPlugin
{
    public string Name => "Hello";

    public void Execute()
    {
        Console.WriteLine("Hello from plugin.");
    }
}

アプリ本体側では、読み込んだ型から IPlugin を実装しているものを探します。

using System.Reflection;
using PluginContracts;

Assembly assembly = Assembly.LoadFrom(@"C:\Plugins\HelloPlugin.dll");

Type? pluginType = assembly.GetTypes()
    .FirstOrDefault(type =>
        typeof(IPlugin).IsAssignableFrom(type) &&
        type is { IsClass: true, IsAbstract: false });

if (pluginType == null)
{
    Console.WriteLine("プラグイン型が見つかりません。");
    return;
}

IPlugin plugin = (IPlugin)Activator.CreateInstance(pluginType)!;

Console.WriteLine(plugin.Name);
plugin.Execute();

この形にすると、実行時に型を探しつつ、呼び出し自体はインターフェイス経由で型安全にできます。

フレームワークのアセンブリを調べる

リフレクションは、自分のアセンブリだけでなく、フレームワークの型にも使えます。

using System.Reflection;

Type type = typeof(HttpClient);
Assembly assembly = type.Assembly;

Console.WriteLine(assembly.FullName);

foreach (MethodInfo method in type.GetMethods()
    .Where(m => m.Name.Contains("Async")))
{
    Console.WriteLine(method.Name);
}

ドキュメント生成、API 調査、学習用ツールなどで役立ちます。

動的読み込み時の注意点

外部 DLL を読み込む設計では、次の点に注意します。

  • 読み込む DLL の信頼性
  • 依存アセンブリの解決
  • バージョン違い
  • 例外の隔離
  • 実行権限
  • アンロードが必要かどうか

特に、ユーザーが自由に置ける DLL を読み込む場合は、セキュリティ上の境界として扱うべきではありません。
同じプロセス内で実行する以上、プラグインはアプリ本体へ大きな影響を与えられます。

信頼できないコードを実行する必要があるなら、別プロセス化やコンテナー化など、より強い分離を検討します。

まとめ

外部アセンブリを読み込み、型を探し、インスタンスを作り、メソッドを呼び出すことで、実行時に機能を追加できます。

ただし、文字列でメソッド名を指定する設計は壊れやすいため、実務では共通インターフェイスや属性を組み合わせるのがおすすめです。
次回は、その属性を使って、型やメソッドに意味を付与する方法を見ていきます。

C# .NET リフレクション Activator AssemblyLoadContext プラグイン 動的読み込み
← [C#] リフレクションで型の中身を調べる [C#] 属性でコードに意味を与える →

Related Posts

  • [C#] プラグインで拡張できるアプリケーションを設計する Jul 9, 2026
  • [C#] 属性でコードに意味を与える Jul 8, 2026
  • [C#] リフレクションで型の中身を調べる Jul 6, 2026
  • [C#] 型メタデータとリフレクションの基礎を理解する Jul 5, 2026

Table of Contents

  • 実行時に読み込むとはどういうことか
  • 外部アセンブリを読み込む
  • 型を探す
  • インスタンスを作成する
  • 引数なしメソッドを呼び出す
  • 引数ありメソッドを呼び出す
  • 共通インターフェイスで安全に呼び出す
  • フレームワークのアセンブリを調べる
  • 動的読み込み時の注意点
  • まとめ

Recent Posts

  • [C#] プラグインで拡張できるアプリケーションを設計する Jul 9, 2026
  • [C#] 属性でコードに意味を与える Jul 8, 2026
  • [C#] 外部アセンブリを読み込み実行時に型を呼び出す Jul 7, 2026
  • [C#] リフレクションで型の中身を調べる Jul 6, 2026
  • [C#] 型メタデータとリフレクションの基礎を理解する Jul 5, 2026

Categories

  • C#120
  • .NET119
  • AWS27
  • Laravel16
  • Linux15
  • MySQL9
  • Apache8
  • PHP8
  • DynamoDB6
  • セキュリティ6
  • Nginx5
  • WordPress4
  • インフラ4
  • Hugo3
  • .NET Framework1
  • Aurora1
  • Diagnostics1
  • Filament1
  • Git1
  • SQS1

Tags

  • C#
  • .NET
  • AWS
  • Laravel
  • コレクション
  • PHP
  • セキュリティ
  • MySQL
  • Linux
  • パフォーマンス
  • Apache
  • System.Collections.Generic
  • デリゲート
  • Code Snippet
  • DynamoDB
  • LINQ
  • NoSQL
  • PHP-FPM
  • RDS
  • System.Collections
  • Windows
  • メモリ管理
  • リフレクション
  • DoS
  • Nginx
  • WordPress
  • メタデータ
  • ラムダ式
  • 監視
  • 設計
  • Amazon Linux 2023
  • Delegate
  • Docker
  • IDisposable
  • Ipset
  • Iptables
  • LINQ to Objects
  • OPCache
  • Pointer
  • Reflection
  • System.Collections.Specialized
  • Unsafe
  • Webサーバー
  • インターフェース
  • オブジェクト指向
  • クラス設計
  • デザインパターン
  • パターンマッチング
  • ポインター
  • 継承
Powered by Hugo & Explore Theme.