que programacion metodos metodo funciones estructura ejercicios consola clases c# c#-3.0 lambda

programacion - metodos y funciones en c#



¿Cuál es la sintaxis más suave y atractiva que ha encontrado para afirmar la corrección de parámetros en c#? (14)

Abordé este problema exacto hace unas semanas, después de pensar que es extraño cómo las bibliotecas de prueba parecen necesitar un millón de versiones diferentes de Assert para que sus mensajes sean descriptivos.

Aquí está mi solución .

Breve resumen: dado este pequeño código:

int x = 3; string t = "hi"; Assert(() => 5*x + (2 / t.Length) < 99);

Mi función Assert puede imprimir el siguiente resumen de lo que se le pasa:

(((5 * x) + (2 / t.Length)) < 99) == True where { ((5 * x) + (2 / t.Length)) == 16 where { (5 * x) == 15 where { x == 3 } (2 / t.Length) == 1 where { t.Length == 2 where { t == "hi" } } } }

De modo que todos los nombres y valores de los identificadores, y la estructura de la expresión, podrían incluirse en el mensaje de excepción, sin tener que volver a expresarlos en cadenas entrecomilladas.

Un problema común en cualquier idioma es afirmar que los parámetros enviados a un método cumplen con sus requisitos y, si no lo hacen, enviar mensajes de error agradables e informativos. Este tipo de código se repite una y otra vez, y a menudo intentamos crear ayuda para él. Sin embargo, en C #, parece que esos ayudantes se ven obligados a lidiar con alguna duplicación impuesta sobre nosotros por el lenguaje y el compilador. Para mostrar lo que quiero decir, permítanme presentar algunos códigos en bruto sin ayudantes, seguidos de un posible ayudante. Luego, señalaré la duplicación en el ayudante y formularé mi pregunta con precisión.

Primero, el código sin ayudantes:

public void SomeMethod(string firstName, string lastName, int age) { if(firstName == null) { throw new WhateverException("The value for firstName cannot be null."); } if(lastName == null) { throw new WhateverException("The value for lastName cannot be null."); } // Same kind of code for age, making sure it is a reasonable range (< 150, for example). // You get the idea }

}

Ahora, el código con un intento razonable de ayudante:

public void SomeMethod(string firstName, string lastName, int age) { Helper.Validate( x=> x !=null, "firstName", firstName); Helper.Validate( x=> x!= null, "lastName", lastName); }

La pregunta principal es esta: observe cómo el código debe pasar el valor del parámetro y el nombre del parámetro ("firstName" y firstName). Esto es para que el mensaje de error pueda decir: "Bla bla bla el valor para el parámetro firstName ". ¿Has encontrado alguna forma de evitar esto usando el reflejo o cualquier otra cosa? ¿O una forma de hacerlo menos doloroso?

Y, en términos más generales, ¿ha encontrado otras formas de simplificar esta tarea de validación de parámetros mientras reduce la duplicación de código?

EDITAR: He leído a personas que hablan acerca de hacer uso de la propiedad Parámetros, pero que nunca encontraron una forma de evitar la duplicación. Alguien tiene suerte con eso?

¡Gracias!


Aquí está mi respuesta al problema. Yo lo llamo " Guard Garras ". Utiliza el analizador de IL de Lokad Shared Libs pero tiene un enfoque más directo para establecer las cláusulas de guardia reales:

string test = null; Claws.NotNull(() => test);

Puede ver más ejemplos de su uso en las specs .

Dado que usa lambdas reales como entrada y usa el IL Parser solo para generar la excepción en el caso de una violación, debe tener un mejor rendimiento en la "ruta feliz" que los diseños basados ​​en Expression en otras partes de estas respuestas.

Los enlaces no funcionan, aquí está la URL: http://github.com/littlebits/guard_claws/


Debería verificar los Contratos de Código ; ellos hacen casi exactamente lo que estás preguntando. Ejemplo:

[Pure] public static double GetDistance(Point p1, Point p2) { CodeContract.RequiresAlways(p1 != null); CodeContract.RequiresAlways(p2 != null); // ... }


En este caso, en lugar de usar su propio tipo de excepción, o tipos realmente generales como ApplicationException ... Creo que es mejor utilizar los tipos de excepciones incorporados específicamente para este uso:

Entre ellos ... System.ArgumentException, System.ArgumentNullException ...



Las bibliotecas compartidas de Lokad también tienen una implementación basada en el análisis de IL que evita tener que duplicar el nombre del parámetro en una cadena.

Por ejemplo:

Enforce.Arguments(() => controller, () => viewManager,() => workspace);

Lanzará una excepción con el nombre del parámetro apropiado si alguno de los argumentos enumerados es nulo. También tiene una implementación de reglas realmente ordenada basada en políticas.

p.ej

Enforce.Argument(() => username, StringIs.Limited(3, 64), StringIs.ValidEmail);


Mi preferencia sería simplemente evaluar la condición y pasar el resultado en lugar de pasar una expresión para evaluar y el parámetro para evaluarla. Además, prefiero tener la capacidad de personalizar todo el mensaje. Tenga en cuenta que estas son simplemente preferencias, no digo que su muestra sea incorrecta, pero hay algunos casos en que esto es muy útil.

Helper.Validate( firstName != null || !string.IsNullOrEmpty(directoryID), "The value for firstName cannot be null if a directory ID is not supplied." );


Muy bien chicos, soy yo otra vez, y encontré algo más que es asombroso y delicioso. Es otra publicación de blog a la que se hace referencia desde la otra pregunta de SO que Chris mencionó anteriormente.

El enfoque de este tipo te permite escribir esto:

public class WebServer { public void BootstrapServer( int port, string rootDirectory, string serverName ) { Guard.IsNotNull( () => rootDirectory ); Guard.IsNotNull( () => serverName ); // Bootstrap the server } }

Tenga en cuenta que no hay ninguna cadena que contenga "directorio raíz" y ninguna cadena que contenga "nombreServidor". Y sin embargo, sus mensajes de error pueden decir algo como "El parámetro de directorio raíz no debe ser nulo".

Esto es exactamente lo que quería y más de lo que esperaba. Aquí está el enlace a la publicación del blog del tipo.

Y la implementación es bastante simple, de la siguiente manera:

public static class Guard { public static void IsNotNull<T>(Expression<Func<T>> expr) { // expression value != default of T if (!expr.Compile()().Equals(default(T))) return; var param = (MemberExpression) expr.Body; throw new ArgumentNullException(param.Member.Name); } }

Tenga en cuenta que esto hace uso de "reflexión estática", por lo que en un ciclo cerrado o algo así, es posible que desee utilizar el enfoque anterior de Rick Brewster.

Tan pronto como publique esto voy a votar a Chris, y la respuesta a la otra pregunta SO. ¡Estas son algunas cosas buenas!


No sé si esta técnica se transfiere de C / C ++ a C #, pero lo he hecho con macros:

#define CHECK_NULL(x) { (x) != NULL || / fprintf(stderr, "The value of %s in %s, line %d is null./n", / #x, __FILENAME__, __LINE__); }


No se aplica en todas partes, pero podría ayudar en muchos casos:

Supongo que "SomeMethod" está llevando a cabo alguna operación de comportamiento en los datos "apellido", "primer nombre" y "edad". Evalúa tu diseño de código actual. Si los tres datos están llorando por una clase, póngalos en una clase. En esa clase también puedes poner tus cheques. Esto liberaría "SomeMethod" de la comprobación de entrada.

El resultado final sería algo como esto:

public void SomeMethod(Person person) { person.CheckInvariants(); // code here ... }

La llamada sería algo como esto (si usa .NET 3.5):

SomeMethod(new Person { FirstName = "Joe", LastName = "White", Age = 12 });

bajo el supuesto de que la clase se vería así:

public class Person { public string FirstName { get; set; } public string LastName { get; set; } public int Age { get; set; } public void CheckInvariants() { assertNotNull(FirstName, "first name"); assertNotNull(LastName, "last name"); } // here are your checks ... private void assertNotNull(string input, string hint) { if (input == null) { string message = string.Format("The given {0} is null.", hint); throw new ApplicationException(message); } }

En lugar del azúcar sintáctico de .NET 3.5 también puede usar argumentos de constructor para crear un objeto Person.


Solo como contraste, this publicación de Miško Hevery en el Blog de Pruebas de Google sostiene que este tipo de comprobación de parámetros no siempre es buena. El debate resultante en los comentarios también plantea algunos puntos interesantes.


Usando mi biblioteca The Helper Trinity :

public void SomeMethod(string firstName, string lastName, int age) { firstName.AssertNotNull("firstName"); lastName.AssertNotNull("lastName"); ... }

También admite afirmar que los parámetros de enumeración son correctos, las colecciones y sus contenidos no son null , los parámetros de cadena no están vacíos, etcétera. Consulte la documentación del usuario here para ver ejemplos detallados.


Wow, encontré algo realmente interesante aquí. Chris arriba dio un enlace a otra pregunta de Desbordamiento de pila. Una de las respuestas allí apuntaba a una publicación de blog que describe cómo obtener un código como este:

public static void Copy<T>(T[] dst, long dstOffset, T[] src, long srcOffset, long length) { Validate.Begin() .IsNotNull(dst, “dst”) .IsNotNull(src, “src”) .Check() .IsPositive(length) .IsIndexInRange(dst, dstOffset, “dstOffset”) .IsIndexInRange(dst, dstOffset + length, “dstOffset + length”) .IsIndexInRange(src, srcOffset, “srcOffset”) .IsIndexInRange(src, srcOffset + length, “srcOffset + length”) .Check(); for (int di = dstOffset; di < dstOffset + length; ++di) dst[di] = src[di - dstOffset + srcOffset]; }

No estoy seguro de que sea la mejor respuesta hasta el momento, pero ciertamente es interesante. Aquí está la publicación del blog , de Rick Brewster.