5

私の次のコードをチェックしてください...

public enum LogType
{
    Debug,
    Info,
    Warn,
    Error,
    Fatal
}

private static readonly ILog log = 
log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

public void LogError(LogType logtype, string message)
{
    XmlConfigurator.Configure();
    if (logtype == LogType.Debug)
        log.Debug(message);
    else if (logtype == LogType.Error)
        log.Error(message);
}

私は上記のすべての if-else ステートメントが好きではなく、これを書くためのよりクリーンな方法があると信じています。どうすればリファクタリングできますか? log クラスには、Debug、Error などのさまざまなメソッドがあります。

メソッドを1回呼び出して、自動的に処理したいと思います。

LogMyError(LogType.Debug, "I am just logging here");

どうすればそのようなことができますか?私はswitchステートメントから離れることを好みます。クリーンなオブジェクト指向のアプローチを探しています。

4

6 に答える 6

16

あなたのコードはそのままで問題ありません。私はそれを変更しません。

ただし、より「オブジェクト指向」になりたい場合は、これをどのよう行うかを考えることは有益です。あなたの 2 つのケースを考えてみましょう。他のものは、それらがどのように実装されるかを簡単に確認できます:

public abstract class LogType
{
    public static readonly LogType Debug = new LogTypeDebug();
    public static readonly LogType Error = new LogTypeError();

    private LogType() {} // Prevent anyone else from making one.

    public abstract void LogMessage(ILog logger, string message);

    private sealed class LogTypeDebug: LogType
    {
        public override void LogMessage(ILog logger, string message)
        {
            logger.Debug(message);
        }
    }

    private sealed class LogTypeError: LogType
    {
        public override void LogMessage(ILog logger, string message)
        {
            logger.Error(message);
        }
    }
}
...

//Obtain the log object the way you prefer.
private static readonly ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

public void LogError(LogType logtype, string message)
{
    logtype.LogMessage(log, message);
}

コールサイトは一切変わりません!それはまだ次のように見えます:

LogError(LogType.Debug, "my message");

そして、そこに行きます:いいえiforswitchステートメントはまったくありません!「型を切り替える」コードは、仮想関数テーブルに移動されました。これは、オブジェクト指向コードに属する場所です。

この手法の優れた副作用は、誰かが整数を列挙型のサポートされていない値にキャストすることを心配する必要がないことです。LogType 型の変数に指定できる値は、null またはシングルトンの 1 つへの参照のみです。

于 2012-04-05T21:07:54.193 に答える
11

a を使用しDictionary<LogType,Action<string>>て、各列挙値に対して実行するアクションを保持し、デリゲートを呼び出すだけです。

var logActions = new Dictionary<LogType,Action<string>>();
logActions.Add(LogType.Debug, log.Debug);
...

logActions[logtype](message);

アップデート:

ifステートメントに少数のブランチしかない場合、これはすべてやり過ぎです。私はこの方法を5つ以上のifに使用します。

于 2012-04-05T20:51:53.857 に答える
5

Imo、コードを変更する明らかな理由はありません。機能は明確で、明確なif/else定義をしています。関数宣言をすることで、自分の使いたいように使うことができます。

したがって、表示されているコードは何も変更しません。

幸運を。

于 2012-04-05T20:52:37.370 に答える
3

スイッチ ブロックを使用します。

switch (logtype)
{
    case LogType.Debug:
        log.Debug(message);
        break;

    case LogType.Error:
        log.Error(message);
        break;

    //more cases here as needed...

    default:
        throw new InvalidArgumentException("logtype");
}
于 2012-04-05T20:50:04.220 に答える
0

常に次のswitchステートメントがあります。

switch (logtype)
{
    case LogType.Debug:
        log.Debug(message);
        break;
    case LogType.Error:
        log.Error(message);
        break;
    ....
}
于 2012-04-05T20:50:28.730 に答える
0

を使用するか、 as キーと対応するメソッドを値として使用switchして辞書を作成することができます - an 、そしてLogTypeLogXXXXAction<string>

myDictionary[logType](message);
于 2012-04-05T20:53:56.647 に答える