2012-04-05 10 views
5

Por favor revise mi siguiente código ...C# refactorizar código si-else

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); 
} 

no me gusta todas las declaraciones si-si no por encima y por creer que hay una forma más limpia de escribir esto. ¿Cómo podría refactorizarlo? la clase de registro tiene diferentes métodos para Depurar, Error, etc.

Me gustaría hacer una sola llamada a un método para que se ocupe automáticamente de ello.

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

¿Cómo puedo hacer tal cosa? Prefiero mantenerme alejado de la declaración de cambio. Estoy buscando un enfoque orientado a objetos limpios.

+2

¿No es eso lo que ya estás haciendo? – Matthew

+0

Además del bloque de conmutadores, no dedicaría demasiado tiempo a pensar en un patrón de refactorización si solo son las 2 opciones para elegir. Es perfectamente legible de esta manera. – Alex

+0

Yo tampoco veo el motivo de ningún cambio: para la refactorización o cualquier mejora en el diseño, generalmente debe tener una razón por la cual, qué es lo que intenta 'resolver' o mejorar, simplificar etc. No lo hago mira que aquí, un método simple ya lo hace, usa el interruptor si hay más 'tipos' – NSGaga

Respuesta

11

Puede utilizar un Dictionary<LogType,Action<string>> para sostener las acciones a realizar para cada valor de la enumeración, a continuación, sólo llamar al delegado.

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

logActions[logtype](message); 

Actualización:

Todo esto es una exageración si sólo tiene un pequeño número de ramas en sus declaraciones if. Usaría este método para más de 5 tales ifs.

+0

Oded ... gracias ... ¿puedo obtener un ejemplo de código si es posible ... Soy nuevo en esto. –

+0

@ dotnet-practitioner - Ejemplo dado, aunque asume que ya tienes una instancia de 'log' en alguna parte. – Oded

+0

Parece un poco exagerado si sabes de antemano que solo va a haber dos valores, error y depuración. – Servy

3

Utilice un switch block:

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"); 
} 
0

Siempre existe la switch declaración:

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

Imo, no hay razones aparentes para cambiar nada en su código. La función es clara y deja clara if/else definición. La declaración de función le permite usarla de una manera que solo quiere usarlo.

Así que no cambiaría nada en el código que veo.

Buena suerte.

0

Puede utilizar un switch o crear un diccionario con el LogType como la clave y el correspondiente método de LogXXXX como un valor - un Action<string>, y luego hacer

myDictionary[logType](message); 
15

su código es perfectamente bien tal como es; No lo cambiaría

Sin embargo, es instructivo pensar en cómo haría hacer esto si quería ser más "orientado a objetos" al respecto. Consideremos dos de sus casos; los otros puede ver fácilmente cómo se implementarían:

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); 
} 

¡El sitio de llamadas no cambia en absoluto! Todavía se parece a:

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

Y hay que ir: no hay if o switch declaraciones en absoluto!El código "cambiar el tipo" se movió a en la tabla de funciones virtuales, que es donde pertenece al código orientado a objetos.

Un buen efecto secundario de esta técnica es que nunca tiene que preocuparse de que alguien arroje un número entero a un valor no admitido de su tipo enumerado. Los únicos valores posibles para una variable de tipo LogType son nulos o una referencia a uno de los singletons.

+0

Este es absolutamente el enfoque que tomaría si tuviera más de una 'Acción ' para encender. – Oded

+0

Eric, parece que mi GetLogger es diferente a su GetLogger –

+2

@ dotnet-practitioner: Y eso es relevante para la pregunta ¿cómo? No estoy siguiendo tu línea de pensamiento aquí. El objetivo de la respuesta fue demostrarle cómo realizar esta tarea de forma orientada a objetos; ¿No está claro de alguna manera? –

Cuestiones relacionadas