3

アプリケーションのロギングタスク(.NET 3.5)には、社内の単純なLoggerクラスを使用しています。

ロガーコードはかなり古く、次のように設計されています。

public class Logger : ILogger
{
     private ILogger instance;

     private static ILogger Instance
     { 
         // Initialized on first use.
         get { return instance; }
     }

     public static void Debug(string msg)
     {
           instance.Debug(msg);
     }

     public static void Error(string msg)
     {
           ....
     }
}

インスタンス自体は、最初の使用時に(遅延して)初期化されています。

これは、厳密な「本による」実装によるとシングルトンではありませんが、それでも、すべての呼び出し元コードからのこのクラスへのアクセスは静的アクセスです。

テスト目的やその他のアーキテクチャ上の理由から、内部インスタンスを別のものに置き換える(注入する)ことができるようにしたいと思います。

どうすればこれを簡単に達成できますか?現時点ではIoCコンテナを使用していませんが、セッターをInstanceプロパティに公開したくないのは、シングルトンのようなデザイン全体が無効になるためです。

これに対する解決策を考え出す方法について何か提案はありますか?

4

5 に答える 5

2

テスト目的でFakes Frameworkを使用することを検討してください。このようなもので静的メソッドへの呼び出しをスタブすることができます

ShimLogger.Instance = () => new LoggerMock();

.net 3.5 の場合、Moles Frameworkを使用して静的メソッド呼び出しをスタブ化できます。構成コードは次のようになります。

MLogger.Instance = () => new LoggerMock();

静的メソッドを公開する必要がありますInstanceが、この構成の後、静的メソッドへのすべての呼び出しはモック化されたインスタンスを返します。

于 2012-08-21T19:23:12.250 に答える
1

確かに、セッターは良い選択とは思えません。

代わりに、2 つの可能なアプローチを検討します。まず、明示的な構成方法:

public class Logger : ILogger {

  public void ConfigureLogger( ILogger logger ) {
     this.instance = logger;
  }

}

このようなアプローチの利点は、意図が明確であり、このメソッドを明示的に呼び出す必要があることです。

別のオプションは、構成でロガーのタイプを渡すことを許可することです。

<appSettings>
    <add key="loggerType" value="The.Type.From, Some.Assembly" />
</appSettings>

次に、Loggerクラスで初期化ルーチンを書き直して、構成パラメーターが存在する場合に、構成で提供される型をデフォルトの型より優先するようにします。

このようなアプローチの利点は、コードを変更せずに構成を変更してクライアントを再構成できることです。

とにかく、IoC コンテナーは食いつきません。長期的に見れば効果があるので紹介します。

于 2012-08-21T19:22:49.833 に答える
0

ロガーを使用してコードを変更します。Logger.Instance を介してロガーにアクセスする代わりに、目的のロガーのインスタンスをオブジェクトに渡します。次に、ファクトリやコンポジション ルートで Logger.Instance をプロダクション コードのロガーのソースとして渡します。ユニット テストでは、モック ロガーを簡単に使用できます。

public class Foo
{
  private readonly ILogger logger;

  public Foo(ILogger logger)
  {
    if (logger == null)
      throw new ArgumentNullException("logger");
    this.logger = logger;
  }

  public void Func()
  {
    try
    {
      // do something
    }
    catch (Exception ex)
    {
      // call the provided logger dependency
      this.logger.WriteError(ex);

      // not the static singleton property
      Logger.Instance.WriteError(ex);
    }
  }
}
于 2012-08-21T19:31:37.090 に答える
0

もう 1 つのアイデアは、プロパティのinternalセッターを作成し、 InternalsVisibleTo属性を使用して内部セッターをテスト アセンブリから見えるようにすることです。ロガーを含むアセンブリに厳密な名前が付いている場合は、属性でを指定する必要があることに注意してください。ロガーが独自のアセンブリまたはほとんどの開発/ロギングが行われていないある種のインフラストラクチャ アセンブリにある場合、これは明らかに最も役立ちます (他の開発者が誤って (または意図的に) インスタンスを別のものに設定できないようにするという意味で)。 .InstancePublicKeyInternalsVisibleTo

于 2012-08-21T19:38:10.683 に答える
0

私はあなた自身を転がしません。ほとんどすべてのロギング ニーズに Enterprise Library を使用しています。デスクトップおよびasp.netプロジェクトで動作します。Asp.net は、サーバー上のセキュリティに対処する必要があるため、もう少し問題がある可能性がありますが、私はそれを行いました。

http://entlib.codeplex.com/

人々は Log4Net も気に入っていますが、私は使ったことがないのでコメントできません。

于 2012-08-21T19:21:53.617 に答える