devlights
4/22/2013 - 7:59 AM

出力処理を実行時に動的に適用するサンプル

出力処理を実行時に動的に適用するサンプル

同じ事が実現できるライブラリはたくさんあると思うが、ここは自前で簡単に実装してみる。 やることは以下の通り。

  • 共通ライブラリ用のプロジェクトを作る (Samples.Common)
  • 何かを出力するクラスを持つクラスライブラリを作る (Samples.Lib)
  • コンソールから実行するコンソールアプリを作る (Samples.Cui)
  • 共通ライブラリプロジェクトを Samples.LibとSamples.Cuiに参照設定
  • Samples.Libプロジェクトは実行時に読み込むのでSamples.Cuiで参照設定しない
  • Samples.Libのビルド後イベントにて出来上がったDLLをSamples.Cuiの実行ディレクトリにコピーするようにする
    • COPY $(TargetPath) $(SolutionDir)Samples.Cui$(OutDir)

以下コード。
インターフェースたち (Samples.Common)(共通ライブラリ)

namespace Samples.Common
{
  using System;
  using System.Collections.Generic;
  using System.Linq;

  public interface IExecutable
  {
    void Execute();
  }
  
  public interface IOutputManager
  {
    void Write(object data);
    void WriteLine(object data);
  }
}

出力管理クラス (Samples.Common)(共通ライブラリ)

namespace Samples.Common
{
  using System;
  using System.Collections.Generic;
  using System.Linq;

  public static class Output
  {
    private static IOutputManager _Manager;

    public static void SetOutputManager(IOutputManager manager)
    {
      _Manager = manager;
    }

    public static void Write(object data)
    {
      Defence();
      _Manager.Write(data);
    }

    public static void WriteLine(object data)
    {
      Defence();
      _Manager.WriteLine(data);
    }

    private static void Defence()
    {
      if (_Manager == null)
      {
        throw new InvalidOperationException("No OutputManager was found. please call SetOutputManager(IOutputManager) before your first access");
      }
    }
  }
}

サンプルクラス (Samples.Lib)(サンプルライブラリ)

namespace Samples.Lib
{
  using System;
  using System.Collections.Generic;
  using System.Linq;
  
  using Samples.Common;

  public class Sample01 : IExecutable
  {
    public void Execute()
    {
      Output.WriteLine("hello world");
    }
  }
}

クライアントアプリ (Samples.Cui)(コンソールアプリ)

namespace Samples.Cui
{
  using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Reflection;
  
  using Samples.Common;
  
  class Program
  {
    static void Main()
    {
      Output.SetOutputManager(new CuiOutputManager());

      // (1) アセンブリを直接ロードしてインスタンス作成
      var asm = Assembly.Load("Samples.Lib");
      var sample = (IExecutable) asm.CreateInstance("Samples.Lib.Sample01");
      // (2) Activator経由でアセンブリのロードとインスタンス作成
      //var sample = (IExecutable) Activator.CreateInstance("Samples.Lib", "Samples.Lib.Sample01").Unwrap();

      sample.Execute();

      Console.WriteLine("press any key to exit...");
      Console.ReadKey();
    }
  }
  
  public class CuiOutputManager : IOutputManager
  {
    public void Write(object data)
    {
      Console.Write(data);
    }

    public void WriteLine(object data)
    {
      Console.WriteLine(data);
    }
  }
}