visual tipos studio que objetos float ejemplos declaracion datos clases c# refactoring structure if-statement guard-clause

que - tipos de datos en c# visual studio



¿Cómo debería reescribir un compuesto muy grande si la declaración en C#? (18)

Aunque me gusta la solución de Dario (como comenté, la pondría en una función booleana, así que no tenía que tener una nueva en la condición de una ...) No estoy seguro de qué pasa con:

if((something == -1) && (somethingElse == -1) && (elseElse == -1) && ... )

Creo que es mucho más fácil de leer que una gran cantidad de ((A && B) || (C && (D || E))) con los que tengo que lidiar ...

En mi código C #, tengo una declaración if que comenzó inocentemente:

if((something == -1) && (somethingelse == -1) && (etc == -1)) { // ... }

Está creciendo. Creo que ahora debe haber 20 cláusulas.

¿Cómo debería manejar esto?


Factorizarlo en una función y hacer de cada condición una cláusula de guardia:

int maybe_do_something(...) { if(something != -1) return 0; if(somethingelse != -1) return 0; if(etc != -1) return 0; do_something(); return 1; }


Hago esto de una manera que a nadie le gusta excepto a mí. No me importa si el código "se ve bien". Si tengo> 1 prueba en ese condicional, eso significa que es probable que desee aún más, o puedo querer comentar algunos de ellos dentro o fuera, y quiero simplificar la realización de dichos cambios.

Así que lo codifico así:

if (true && test_1 && test_2 ... ) { ... }

Esto hace que sea más fácil comentar pruebas, o agregar nuevas, como ediciones de 1 línea.

Pero seré el primero en admitir que no pretende ser bonita.


Hay muchas maneras de manejar esto, pero déjame elegir algunas.

En primer lugar, está el caso donde todos los criterios (todos los criterios AND en su instrucción if) + el código a ejecutar si son todos verdaderos es una situación única.

En este caso, usa el código que tienes. Es posible que desee hacer lo que varios otros ya han sugerido, vuelva a escribir para usar un tipo de código de cláusula Guard.

En otras palabras, en lugar de esto:

if (a && b && c && d && ......) DoSomething();

... reescribes a algo similar a esto:

if (!a) return; if (!b) return; if (!c) return; if (!d) return; if (!...) return; DoSomething();

¿Por qué? Porque una vez que comienzas a introducir los criterios de OR en la mezcla, es difícil leer el código y descubrir qué va a pasar. En el código anterior, divide los criterios en cada AND-operator (&&), y así el código se vuelve más fácil de leer. Básicamente reescribes el código diciendo "si esto y aquello, o esa otra cosa y esa tercera cosa, o alguna otra cosa, luego haces algo" para ser "si esto, luego salgas; si esa otra cosa, luego sales; otra cosa; luego salga; si nada de lo anterior, haga algo ".

Sin embargo, en muchos casos, también tiene el caso de la reutilización. Si algunos de esos criterios aparecen en otro lugar, pero el código que realmente se ejecutará (DoSomething) no es el mismo, entonces volveré a buscar lo que otros ya han sugerido. Vuelva a escribir los criterios en métodos que devuelvan un resultado Boolean según el resultado de evaluar los criterios.

Por ejemplo, ¿qué es más fácil de leer, esto?

if (a && b && c && d && e && f && (h || i) && (j || k) || l)

o esto:

if (CanAccessStream() && CanWriteToStream())

asumiendo que todas esas letras se pueden dividir en esos dos criterios.

En ese caso, tomaría algunos de los criterios y los pondría en esos métodos, y elegiría un nombre apropiado para los criterios.

La tercera opción es cuando el criterio difiere en varios lugares en el código, pero el código real para ejecutar es el mismo.

En este caso, volvería a escribir para que agrupe los criterios y superponga los métodos de manera que llamar a un método verifique algunos criterios y luego llame a otro método, que verificará otros criterios, etc.

Por ejemplo, podrías escribir esto:

if (stream != null && buffer != null && inBuffer > 0 && stream.CanWrite) stream.Write(buffer, 0, inBuffer); else throw new InvalidOperationException();

o podrías escribir esto:

if (inBuffer > 0) { Debug.Assert(buffer != null); WriteToStream(buffer, inBuffer); } ... private void WriteToStream(Byte[] buffer, Int32 count) { if (stream.CanWrite) stream.Write(buffer, 0, count); else throw new InvalidOperationException(); }

Diría que la segunda forma es más fácil de leer y más reutilizable que la primera.


No es tan común ver tantas cláusulas en un "si". Por lo general, encuentra que necesita anidar el "si" para obtener la lógica que necesita, cuando necesita ejecutar alguna línea, independientemente de la verdad de algunas condiciones. No estoy diciendo que los anides si no es necesario, si todos necesitan ser evaluados al mismo tiempo. Solo si hay alguna funcionalidad común. Otra consideración es establecer una variable booleana con el resultado de un conjunto de estas condiciones, que podría facilitar su comprensión. Si sus variables son una matriz o colección, ¿podría recorrerlas? ¿Los estás probando contra -1?


No sé C #, pero parece incluir el operador condicional . Si sus condiciones son cortas, puede reemplazar cadenas largas if / elsif / else con estructuras similares a una mesa, como esta:

return something == 0 ? 0 : somethingelse == -1 ? 1 : yetanotherthing > 2 ? 2 : 3; # default


Otra vía que puede explorar es el uso de expresiones compuestas. Estas expresiones (que son la base de cómo funciona LINQ en .NET Framework) le permiten crear árboles de expresión basados ​​en todas estas condiciones y luego el código de lógica de negocios simplemente puede operar en la expresión de nivel superior para obtener el resultado verdadero / falso .

Para evaluar las expresiones, puede hacer uso del patrón de visitante

Esto le permite componer fácilmente árboles de las condiciones. estos árboles se pueden serializar incluso para permitirle persistir en las condiciones bajo las cuales tomó la decisión. Se presentan muchas oportunidades aquí.


Parece que tiene 3 piezas de información que juntas representan un estado particular en su aplicación. En lugar de encender estas 3 piezas de estado, ¿por qué no crear un valor que las encapsula? Luego, podría usar una jerarquía de objetos o un delegado en el momento de la creación para vincular la acción que está tratando de ejecutar.


Podría refactorizarlo como una función y devolver un valor Enum que represente el caso que era verdadero:

if(something != -1) return MyEnum.Something; if(somethingelse != -1) return MyEnum.SomethingElse; if(etc != -1) return MyEnum.SomethingElseEntirely; return MyEnum.None;


Realice operaciones agregadas en una lista de sus valores.

if (new[] { something, somethingelse, ... }.All(x => x == -1)) { }

* Editar: dando a los datos una línea adicional:

var Data = new[] { something, somethingelse, ... }; if (Data.All(x => x == -1)) { }


Refactorizarlo a una función.

bool Check() { return (something == -1) && (somethingelse == -1) && (etc == -1); }

Alternativamente, puede construir código / lógica más legible en su función de verificación.


Si realmente tiene que controlar todas estas condiciones, no puede deshacerse de ellas. Solo puede refactorizarlo y hacerlo más legible, pero la lógica permanece igual.

Estoy bastante sorprendido de que nadie haya mencionado nada sobre el rediseño de tu código. ¿Realmente necesitas 20 estados diferentes? En mi experiencia, muchos estados a menudo dependen de otros estados y, por lo tanto, a menudo son lógicamente redundantes para contrastar.

La refacturación de su código puede ayudarlo a comprenderlo mejor y cómo los estados están acoplados entre sí. Empezaría aquí primero si fuera tú :)


Suponiendo que todas esas condiciones son realmente necesarias, puede consolidar las condiciones en uno o más súper-booleanos o llamadas a funciones para mejorar la legibilidad.

P.ej,

bool TeamAIsGoForLaunch = BobSaysGo && BillSaysGo; bool TeamBIsGoForLaunch = JillSaysGo && JackSaysGo; if (TeamAIsGoForLaunch && TeamBIsGoForLaunch && TeamC.isGoForLaunch())


También podría factorizar el estado en una clase.

class mystate { int something; int somethingelse; int etc; bool abletodostuff() { return (something == -1) && (somethingelse == -1) && (etc == -1); } }


Una cosa a considerar es por qué tienes tantas cláusulas. Así como las declaraciones SWITCH a menudo indican que debe mover las elecciones a subclases, una gran cadena compleja de declaraciones IF puede indicar que está combinando demasiados conceptos (y, por lo tanto, decisiones) en un solo lugar.

Como ejemplo, usaré el ejemplo de cálculo de comisión. En un sistema que construí, la tasa de comisión depende de la cantidad de comisión otorgada al mayorista, que transfiere un poco al minorista. El monto entregado por un mayorista al minorista depende del acuerdo específico entre el minorista y el mayorista (basado en un contrato). La cantidad que obtiene el mayorista depende de la línea de producto, producto específico y cantidad del producto vendido.

Más allá de esto, había reglas adicionales de "excepción" basadas en el estado del cliente, personalizaciones específicas de productos, etc. Todo esto podría resolverse en una compleja cadena de declaraciones IF, pero en su lugar hicimos que la aplicación manejara los datos.

Al poner toda esta información en tablas, pudimos hacer pases en las reglas de datos. En primer lugar, se desencadenarían las reglas genéricas del mayorista y se desencadenarían las reglas de anulación. Luego, teniendo a mano la comisión de mayorista base, ejecutaremos al mayorista a las reglas genéricas del minorista y luego a las excepciones.

Esto convirtió una gran bola de la lógica en un proceso simple de cuatro pasos, con cada paso simplemente haciendo una consulta en la base de datos para encontrar la regla correcta para aplicar.

Esto, por supuesto, puede no aplicarse en su situación, pero a menudo un complejo grande como ese realmente significa que o no hay suficientes clases dividiendo la responsabilidad (otra solución a nuestro problema podría haber sido las clases de fábrica que contenían las reglas específicas e invalidaciones), o la funcionalidad debe ser impulsada por datos.


Use puertas donde sea posible.

la declaración if

if(bailIfIEqualZero != 0 && !string.IsNullOrEmpty(shouldNeverBeEmpty) && betterNotBeNull != null && !betterNotBeNull.RunAwayIfTrue && //yadda

la versión refactorizada

if(bailIfIEqualZero == 0) return; if(string.IsNullOrEmpty(shouldNeverBeEmpty)) return; if(betterNotBeNull == null || betterNotBeNull.RunAwayIfTrue) return; //yadda


Y algo como esto

Explicaré un poco más. (Y arregle los errores estúpidos: S)

//Interface to be able to which classes are able to give a boolean result used in the if stuff public interface IResultable { bool Result(); } //A list that is IResultable itself it gathers the results of the IResultables inside. public class ComparatorList<T> : List<T>, IResultable where T : IResultable { public bool Result() { bool retval = true; foreach (T t in this) { if (!t.Result()) { retval = false; } } return retval; } } //Or two bools public class OrComparator : IResultable { bool left; bool right; public OrComparator(bool left, bool right) { this.left = left; this.right = right; } #region IResultable Members public bool Result() { return (left || right); } #endregion } // And two bools public class AndComparator : IResultable { bool left; bool right; public AndComparator(bool left, bool right) { this.left = left; this.right = right; } #region IResultable Members public bool Result() { return (left && right); } #endregion } // compare two ints public class IntIsComparator : IResultable { int left; int right; public IntIsComparator(int left, int right) { this.left = left; this.right = right; } #region IResultable Members public bool Result() { return (left == right); } #endregion }

¿Tienes un montón de declaraciones si esto podría ser genial :)

Así que tenemos esta oportunidad para manejar muchas comparaciones. Daré una pequeña implementación de ejemplo.

//list of ands ComparatorList<AndComparator> ands = new ComparatorList<AndComparator>(); ands.Add(new AndComparator(true,true)); //list of ors ComparatorList<OrComparator> ors = new ComparatorList<OrComparator>(); ors.Add(new OrComparator(false, true)); //list of intiss ComparatorList<IntIsComparator> ints = new ComparatorList<IntIsComparator>(); ints.Add(new IntIsComparator(1, 1)); //list of all things :) ComparatorList<IResultable> collected = new ComparatorList<IResultable>(); collected.Add(ands); collected.Add(ors); collected.Add(ints); // if all things are as they must be :) if (collected.Result()) { //Evertything is as it schould be :) }


dices que estás mirando cadenas, ¿qué tal algo como esto que ya se haya comentado?

var items = new List<string>(); items.Add("string1"); items.Add("string2"); if (items.Contains("string2")) { // do something }

incluso podría tomar los valores de un archivo de configuración de algún tipo para completar la lista.