example - Forzar argumentos nombrados en C#
remarks c# (4)
C # 4 introdujo una característica llamada argumentos nombrados que es especialmente útil en escenarios como
int RegisterUser(string nameFirst, string nameLast, string nameMiddle, string email)
¿Hay alguna manera de forzar el uso de argumentos con nombre? ¿Tal vez algún atributo para aplicar a un método o un compilador del que no estoy enterado? Supongo que se puede hacer con las herramientas de inspector de código, pero solo quiero saber si hay otra forma.
PD
Para aquellos interesados en por qué uno puede necesitarlo y por qué no simplemente usar una clase / estructura para utilizar los inicializadores de objetos, hay escenarios cuando es imposible. Al igual que las llamadas a bibliotecas que no están bajo tu control o las convenciones de código extraño que tienes que obedecer.
No, no en el lenguaje C #. Siempre aceptará parámetros posicionales si se suministran todos los parámetros.
Puede construir una regla FxCop personalizada o una regla StyleCop para aplicar esto, como se señaló en los comentarios, es probable que una regla de StyleCop le interese (gracias a Kris).
Es posible obligar a las personas que llaman a usar siempre args con nombre. No lo haría en la mayoría de las circunstancias porque es bastante feo, pero depende de qué tan seguro sea el uso del método.
Aquí está la solución:
int RegisterUser(
#if DEBUG
int _ = 0,
#endif
string nameFirst = null,
string nameLast = null,
string nameMiddle = null,
string email = null) { /*...*/ }
El primer parámetro es un maniquí que no se debe usar (y se compila en Release para mayor eficiencia). Sin embargo, asegura que todos los parámetros siguientes deben ser nombrados.
El uso válido es cualquier combinación de los parámetros nombrados:
RegisterUser();
RegisterUser(nameFirst: "Joe");
RegisterUser(nameFirst: "Joe", nameLast: "Smith");
RegisterUser(email: "[email protected]");
Al intentar usar parámetros posicionales, el código no se compilará.
También busqué la forma de forzar argumentos con nombre. Los parámetros opcionales pueden ser peligrosos, especialmente si tiene múltiples parámetros del mismo tipo. Las sobrecargas son casi siempre una solución más segura, pero hay veces en que tienes un método que puede tomar muchas combinaciones de argumentos, por lo que crear 20 sobrecargas para tener en cuenta la posibilidad de siempre es exagerado.
En situaciones extremas en las que es de suma importancia que los argumentos se nombren en todo momento, crearé una clase de argumento sin un constructor definido. En tu caso, podrías hacer esto:
public class UserRegistrationArguments
{
public string nameFirst { get; set; }
public string nameLast { get; set; }
public string nameMiddle { get; set; }
public string email { get; set; }
}
Llámalo así:
RegisterUser(new UserRegistrationArguments { nameFirst = "Bob", nameLast = "Slob" });
También podrías simplificarlo así:
public class UserRegistrationArguments
{
public string nameMiddle { get; set; }
public string email { get; set; }
}
int RegisterUser(string nameFirst, string nameLast, UserRegistrationArguments args = null)
... y haz esto:
RegisterUser("Bob", "Slob", new UserRegistrationArguments { nameMiddle = "Teh" });
De esta manera, solo tienes un parámetro opcional y eso es para tus parámetros opcionales.
Editar: Tal vez no leí el OP correctamente. ¿No estás usando argumentos opcionales? Si no, entonces esta respuesta probablemente no te ayude.
Estoy usando otro método. En mi configuración, tengo 1 parámetro que siempre espero, luego vienen un montón de cadenas opcionales que realmente quiero asegurar que el usuario elija activamente. Así que mi primera cadena en esta lista es un valor de "trampa", que si se establece arroja un error. Me gusta esto:
public HtmlString Toolbar(DynamicEntity target = null, string dontRelyOnParameterOrder = Constants.RandomProtectionParameter, string actions = null, string contentType = null, object prefill = null)
{
if (!Enabled) return null;
protectAgainstMissingParameterNames(dontRelyOnParameterOrder);
var toolbar = new ItemToolbar(target, actions, contentType, prefill);
return new HtmlString(toolbar.Toolbar);
}
private void protectAgainstMissingParameterNames(string criticalParameter)
{
if(criticalParameter != Constants.RandomProtectionParameter)
throw new Exception("when using the toolbar command, please use named parameters - otherwise you are relying on the parameter order staying the same.");
}
Espero que te guste :)