Pregunta

Estoy creando un cliente de chat de red en C # como un proyecto paralelo. Además de los mensajes de texto simples, también tengo comandos de barra inclinada que se pueden ingresar en el TextBox de entrada. Utilicé un enfoque modular al crear una enumeración que contiene todos los comandos y luego decorar esos comandos con atributos.

Los atributos especifican qué comando con barra inclinada se puede ingresar para desencadenar el comando, así como cualquier alias al identificador del comando principal y al uso del comando.

Ejemplo:

public enum CommandType : byte
{
    [PrimaryIdentifier("file"),
     AdditionalIdentifier("f"),
     CommandUsage("[<recipient>] [<filelocation>]")]
    FileTransferInitiation,

    [PrimaryIdentifier("accept"),
     AdditionalIdentifier("a")]
    AcceptFileTransfer,

    // ...
}

Mi problema surge cuando trato de permitir múltiples alias al comando primario. He intentado esto de dos maneras: al permitir duplicados del atributo AdditionalIdentifier , o al hacer el argumento del constructor en AdditionalIdentifier una params string [] .

Con el primero, lo implementé decorando la clase de atributo con AttributeUsage y configurando AllowMultiple en true. Si bien esto realmente logra lo que estoy buscando, siento que podría ser muy ruidoso realmente rápido al tener varias líneas de alias, además de los otros atributos.

El último también funciona, sin embargo, genera el advertencia del compilador CS3016 , y dice que ese enfoque no es compatible con CLS. Obviamente, esto no necesariamente me impide seguir usándolo, pero he aprendido a tratar siempre las advertencias como errores.

Mi pregunta real es si debo ignorar mis objeciones con duplicados y simplemente seguir adelante y usarlas, ¿o hay alguna otra solución que pueda usarse?

Gracias.

¿Fue útil?

Solución

Personalmente, me gustaría con el enfoque Permitir Múltiples: no creo que el " ruido " va a ser un gran problema a menos que realmente tenga montones de identificadores para cada comando. Pero si no te gusta eso y quieres mantenerte en conformidad con CLS, otra solución sería proporcionar constructores sobrecargados para el atributo de identificador adicional:

public AdditionalIdentifierAttribute(string id) { ... }
public AdditionalIdentifierAttribute(string id1, string id2) { ... }
public AdditionalIdentifierAttribute(string id1, string id2, string id3) { ... }

El inconveniente es que esto lo limita a un número predeterminado de identificadores.

Dicho esto, el cumplimiento de CLS es realmente solo una consideración importante si está construyendo una biblioteca que es probable que otros usen (y específicamente de otros idiomas). Si este tipo o la biblioteca es interna a su aplicación, entonces es razonable ignorar las advertencias de cumplimiento de CLS.

EDITAR: Pensando más en esto, tienes muchos atributos en esas enumeraciones. Es posible que desee considerar la creación de una clase de comando abstracta en su lugar, y exponer los identificadores, el uso, etc. como propiedades de esa clase; luego derive tipos concretos de comandos que devuelven los valores apropiados de esas propiedades. Esto potencialmente también le permite mover la lógica de manejo a esos objetos de Comando en lugar de activar el valor de enumeración.

Otros consejos

También puede usar los alias de " params string [] " en el constructor para permitir una lista de argumentos variables:

[AttributeUsage(AttributeTargets.Method)]
class TestAttribute : Attribute
{
    public TestAttribute(params string[] aliases)
    {
        allowedAliases = aliases;
    }

    public string[] allowedAliases { get; set; }

}

Esto te permitiría hacer:

[Test("test1", "test2", "test3")]
static void Main(string[] args)

¿Por qué no tener un único atributo con múltiples propiedades? Haga que la propiedad del alias tome una lista separada por comas. Este es el enfoque que adoptan en MVC para cosas como AuthorizeAttribute for Roles. Internamente, la propiedad analiza la cadena en una matriz para facilitar su uso en la clase de atributo, pero le permite una forma fácil de configurar su configuración.

public class IdentifierAttribute
{
    public string Name { get; set; }
    public string Usage { get; set; }

    private string[] aliasArray;
    private string aliases;
    public string Aliases
    {
         get { return this.aliases; }
         set
         {
             this.aliases = value;
             this.aliasArray = value.Split(',').Trim();
         }
    }
}

Entonces úsalo como:

public enum CommandType : byte
{
     [Identifer( Name = "file", Aliases = "f", Usage = "..." )]
     FileTransferType,

     ...
}

Otro enfoque sería hacer que el atributo tome una matriz de cadenas como un parámetro constructor; de esa manera, conseguirá que el compilador analice la matriz por usted (a costa de un poco más de pegote al aplicar el atributo). :

[Identifiers(new string[] {"Bill", "Ben", "Ted"})]

Un ejemplo rápido de implementación de & amp; usar una técnica así se ve así:

using System;
using System.Collections.ObjectModel;
namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            SomeClass.TellMeAboutYourself();
        }
    }
    public class Identifiers : Attribute
    {
        private string[] names;
        public Identifiers(string[] someNames)
        {
            names = someNames;
        }
        public ReadOnlyCollection<string> Names { get { return new ReadOnlyCollection<string>(names); } }
    }
    [Identifiers(new string[] {"Bill", "Ben", "Ted"})]
    static class SomeClass
    {
        public static void TellMeAboutYourself()
        {
            Identifiers theAttribute = (Identifiers)Attribute.GetCustomAttribute(typeof(SomeClass), typeof(Identifiers));
            foreach (var s in theAttribute.Names)
            {
                Console.WriteLine(s);
            }
        }
    }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top