Ajustes de la aplicación Ayudante -- # campo con generics camp codereview Relacionados El problema

App settings helper


4
vote

problema

Español

El ayudante debe poder establecer un valor predeterminado si el valor no se puede obtener con la clave proporcionada. También hay un BOOL que lanzará un error si el valor clave o el valor predeterminado no pudieron ser recuperados o convertidos.

¿Puedo hacerlo más compacto, más seguro y aún tener la misma funcionalidad?

Se siente como si estuviera usando demasiados bloques de prueba / captura.

  Worker5  
Original en ingles

The helper should be able to set a default value if the value can't be fetched with the provided key. There is also a bool that will throw an error if the key value or the default value could not be fetched or converted.

Can I make it more compact, safer, and still have the same functionality?

It feels like I am using too many try/catch blocks.

using System; using System.Configuration;  namespace Successful.Misc {     public static class AppSettingsHelper     {         private static bool ThrowException { get; set; }         private static object DefaultValue { get; set; }         public static TResult Get<TResult>(string key, Func<TResult> defaultValue = null, bool throwException = false)         {             ThrowException = throwException;             DefaultValue = defaultValue;              var result = default(TResult);             var valueOfKey = ConfigurationManager.AppSettings[key];              if (string.IsNullOrWhiteSpace(valueOfKey))             {                 if (ThrowException && DefaultValue == null)                 {                     throw new ArgumentNullException(valueOfKey,                         $"Failed to get a value for the key {key} in the App.config file.");                 }                  result = GetDefaultValue(defaultValue);             }             else             {                 result = ConvertToResult<TResult>(key, valueOfKey);             }              return result;         }          private static TResult ConvertToResult<TResult>(string key, string valueOfKey)         {             TResult result;              try             {                 result = (TResult)Convert.ChangeType(valueOfKey, typeof(TResult));             }             catch (Exception ex)             {                 if (ThrowException && DefaultValue == null)                 {                     throw new Exception($"Failed to convert {valueOfKey} from type {valueOfKey.GetType()} to the type {typeof (TResult)}", ex);                 }                  result = GetDefaultValue((Func<TResult>)Convert.ChangeType(DefaultValue, typeof(Func<TResult>)));             }              return result;         }          private static TResult GetDefaultValue<TResult>(Func<TResult> defaultValue)         {             var result = default(TResult);              if (defaultValue != null)             {                 try                 {                     result = defaultValue.Invoke();                 }                 catch (Exception ex)                 {                     if (ThrowException)                     {                         throw new Exception($"Failed to to invoke delegate {defaultValue} of type {defaultValue.GetType()}", ex);                     }                 }             }              return result;         }     } } 
     
         
         

Lista de respuestas

6
 
vote
vote
La mejor respuesta
 

Puede, por supuesto, usar un enfoque diferente como @rubberduck sugirió, pero para el caso que se adhiere a este Lo refactoré a esto:

  public static class AppSettingsHelper {        public static TResult GetValue<TResult>(string key, Func<TResult> getDefaultValue = null, bool canThrowException = false)     {         if (string.IsNullOrEmpty(key)) throw new ArgumentNullException(nameof(key));          var result = default(TResult);         var value = ConfigurationManager.AppSettings[key];          try         {             if (string.IsNullOrWhiteSpace(value))             {                 if (getDefaultValue != null)                 {                     result = getDefaultValue(defaultValue);                 }                  if (canThrowException && result == default(TResult))                 {                     throw new ValueNullException(key);                 }                                            }             else             {                 result = ConvertValue<TResult>(value);             }         }         catch(ValueNullExcpetion)         {             // no need to check the 'canThrowException'             throw;         }         catch(ValueConvertExcpetion ex)         {             // no need to check the 'canThrowException'             ex.Key = key;             throw;         }         catch(Exception ex)         {             if (canThrowException) throw new GetValueExcpetion(key, ex);         }          return result;     }      private static TResult ConvertValue<TResult>(string value, bool canThrowException)     {         try         {             var result = (TResult)Convert.ChangeType(valueOfKey, typeof(TResult));             return result;         }         catch (Exception ex)         {             if (canThrowException)             {                 throw new ValueConvertExcpetion(value, typeof(TResult), ex);             }             return default(TResult);         }     }         }   

en mi opinión

  • No necesitas los campos estáticos
  • Debe usar nombres más descriptivos para los métodos y los parámetros, entonces simplemente Get9 <div class="imgbox"> <img id="img1" onload="fadeImage();"> <img id="img2" onload="fadeImage();"> </div> 0 Si es realmente una función <div class="imgbox"> <img id="img1" onload="fadeImage();"> <img id="img2" onload="fadeImage();"> </div> 1 es un mejor nombre Creo que
  • Si usa un <div class="imgbox"> <img id="img1" onload="fadeImage();"> <img id="img2" onload="fadeImage();"> </div> 2 / <div class="imgbox"> <img id="img1" onload="fadeImage();"> <img id="img2" onload="fadeImage();"> </div> 3 es mejor darle un nombre que comienza con puede / tiene / es , etc. Código> <div class="imgbox"> <img id="img1" onload="fadeImage();"> <img id="img2" onload="fadeImage();"> </div> 4 sugiere que es una función
  • No necesita el método 99887766655443315 en absoluto, no tiene mucho valor
  • Puede arrojar excepciones y agregar más información a ellos en un intento / captura de BIG para que no tenga que reenviar valores a los métodos que no necesitan, sino para lanzar excepciones < / li>

Editar:

Podría, por ejemplo, crear algunas excepciones para darle más información al usuario sobre lo que salió mal:

Observe que también moví textos de mensajes a las excepciones para que pueda reutilizarlos y mantener el limpiador 998877766555443316 .

  <div class="imgbox">   <img id="img1" onload="fadeImage();">   <img id="img2" onload="fadeImage();"> </div> 7  
 

You can of course use a different approach as @RubberDuck suggested but for the case you stick to this one I'd refactor it to this:

public static class AppSettingsHelper {        public static TResult GetValue<TResult>(string key, Func<TResult> getDefaultValue = null, bool canThrowException = false)     {         if (string.IsNullOrEmpty(key)) throw new ArgumentNullException(nameof(key));          var result = default(TResult);         var value = ConfigurationManager.AppSettings[key];          try         {             if (string.IsNullOrWhiteSpace(value))             {                 if (getDefaultValue != null)                 {                     result = getDefaultValue(defaultValue);                 }                  if (canThrowException && result == default(TResult))                 {                     throw new ValueNullException(key);                 }                                            }             else             {                 result = ConvertValue<TResult>(value);             }         }         catch(ValueNullExcpetion)         {             // no need to check the 'canThrowException'             throw;         }         catch(ValueConvertExcpetion ex)         {             // no need to check the 'canThrowException'             ex.Key = key;             throw;         }         catch(Exception ex)         {             if (canThrowException) throw new GetValueExcpetion(key, ex);         }          return result;     }      private static TResult ConvertValue<TResult>(string value, bool canThrowException)     {         try         {             var result = (TResult)Convert.ChangeType(valueOfKey, typeof(TResult));             return result;         }         catch (Exception ex)         {             if (canThrowException)             {                 throw new ValueConvertExcpetion(value, typeof(TResult), ex);             }             return default(TResult);         }     }         } 

In my opinion

  • you don't need the static fields
  • you should use more descriptive names for the methods and parameters then simply Get or defaultValue if it's actually a function getDefaultValue is a better name I think
  • if you use a true/false variable it's better to give it a name that begins with can/has/is etc. throwException suggests it's a function
  • you don't need the GetDefaultValue method at all, it doesn't have much value
  • you can throw exceptions and add more information to them in a big try/catch so that you don't have to forward values to the methods that they don't need but for throwing exceptions

EDIT:

You could for example create a few exceptions to give the user more information about what went wrong:

Notice that I also moved message texts into the exceptions so you can reuse them and keep the throws cleaner.

public class ValueNullExcpetion : Exception {     internal ValueNullExcpetion(string key)      {         Key = key;     }      public string Key { get; private set; }      public override string Message =>          $"Failed to get a value for the key \"{Key}\" in the App.config file."; }  public class ValueConvertExcpetion : Exception {     internal ValueConvertExcpetion(string value, Type targetType, Exception innerExeption)          : base(null, innerException)     {         Value = value;         TargetType = targetType;     }      public string Key { get; internal set; }      public string Value { get; private set; }      public Type TargetType { get; private set; }      public override string Message =>          $"Failed to convert {Value} to the type \"{TargetType.Name}\". " +         $"See inner exception for details."; }  public class GetValueExcpetion : Exception {     internal ValueConvertExcpetion(string key, Exception innerException)         base(null, innerException)     {}      public string Key { get; private set; }      public override string Message =>          $"An unexpected exception occured while getting a value for the key \"{Key}\". " +         "See inner exception for details."; } 
 
 
   
   
5
 
vote

Amo simultáneamente y odio dar respuestas como esta, pero siento que tengo que ...

Estás tratando de resolver el problema que todo se almacena como un 9988776655544330 en el archivo App.config, ¿verdad? Bueno, este problema ya ha sido resuelto por el equipo .NET hace mucho tiempo. Exactamente hace 10 años en realidad. La solución solo funciona si está en al menos la versión 2.0 del marco, pero hay relativamente pocas aplicaciones que se ejecutan en algo menos que eso.

de todos modos, en lugar de declarar elementos en la configuración con

  <add key="Application1" value="MyApplication1" />   

Puede escribir su configuración por usando la GUI . Luego, puede usar su configuración muy escrita como esta.

  var mySetting = Properties.Settings.Default.Application1   

que devolvería un String . Puedes usar cualquier tipo que quieras, incluso clases, enumias y estructuras que te has escrito.

 

I simultaneously love and hate giving answers like this, but I feel like I have to...

You're trying to solve the issue that everything is stored as an Object in the App.Config file, right? Well, this problem has already been solved by the .Net team a long time ago. Exactly 10 years ago actually. The solution only works if you're on at least version 2.0 of the framework, but there are relatively few apps out there running on something less than that.

Anyway, instead of declaring items in the config with

<add key="Application1" value="MyApplication1" /> 

You can strong type your settings by using the GUI. Then you can use your strongly typed settings like this.

var mySetting = Properties.Settings.Default.Application1 

Which would return a String. You can use any type you like, even classes, enums, and structs that you've written yourself.

 
 
     
     

Relacionados problema

8  Aplanamiento recursivo de secuencias rápidas  ( Recursive flattening of swift sequences ) 
en aplanar Obtenga todos los controles infantiles de cierto tipo en una UIVIE , se discutieron los métodos para Recursivamente aplanar una estructura similar...

1  Java Gennics, convertir la lista anidada a la matriz  ( Java generics convert nested list to array ) 
Tengo que interactuar con un código antiguo usando matrices anidadas, por lo que tengo que convertir mis listas anidadas a las matrices anidadas. Cualquier id...

7  Implementar una secuencia de Fibonacci genérica en óxido sin usar copia rasgo  ( Implement a generic fibonacci sequence in rust without using copy trait ) 
Estoy tratando de aprender a óxido y soy un principiante. ¿Cómo se hace frente a la implementación de una versión genérica de la secuencia FIBONACCI sin usar ...

2  Organización de código de deserialización de estructura variante  ( Variant structure deserialization code organization ) 
En mi proyecto, trabajo con objeto COM a través de Questions8 . Com Objeto Devoluciones Puntero en Estructura Questions9 , que eché como Sections0 y luego...

1  Implementación rápida equivalente a colecciones  ( Quicksort implementation equivalent to collections sort ) 
Aquí está mi ir a comprender genéricos, 99887776655443312 S y for3 S, así como en los límites de tipo. Creo que lo hice tan cerca de for4 como sea posib...

1  Función de aplanamiento de la matriz genérica  ( Generic array flattening function ) 
Con la ayuda de la comunidad de CodereView, he escrito una función para aplanar una matriz anidada genérica. Lo tengo escrito de varias maneras, pero quiere c...

3  Genéricos anulables - implementando secuencialSearchst en C #  ( Nullable generics implementing sequentialsearchst in c ) 
Para fines de aprendizaje, estoy implementando cierto código de SEDEDWICK & AMP; Los algoritmos de Wayne, cuarta edición . Debido a las características del...

4  Implementación de Singleton usando genéricos  ( Singleton implementation using generics ) 
Hice esto como un ejercicio solo para practicar / mejorar el uso de genéricos. Independiente de lo útil que es esta implementación de un singleton, ¿cómo es...

7  Clase de valor almacenado en caché genérico imitando perezosos <t>  ( Generic cached value class mimicking lazyt ) 
Antes de escribir esto, busqué y encontré una serie de soluciones que hacen uso de un proveedor de almacenamiento en caché para manejar un conjunto de artícul...

7  Array Genérico  ( Generic arraylist ) 
¿Puede alguien recomendar mejoras al método de compresa ()? public class ArrayList<E> { private Object[] array; public static final int DEFAULT_SIZE = 20...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos