Pergunta

Estou criando um cliente de chat rede em C # como um projeto paralelo. Além de mensagens de texto simples, eu também tenho os comandos prefixo de barra que podem ser inseridos na caixa de texto de entrada. Eu usei uma abordagem modular, criando uma enumeração que contém todos os vários comandos e decorar os comandos com atributos.

Os atributos especificar o comando de corte-prefixados podem ser inseridos para acionar o comando, bem como quaisquer aliases para o identificador de comando primário e uso do comando.

Exemplo:

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

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

    // ...
}

Meu problema surge quando tento permitir que vários aliases para o comando principal. Eu tentei isso de duas maneiras:., Permitindo duplicatas do atributo AdditionalIdentifier, ou fazendo o argumento do construtor em AdditionalIdentifier um params string[]

Com o primeiro, eu implementado por decorar a classe atributo com AttributeUsage e definindo AllowMultiple para true. Enquanto isso, de fato, conseguir o que eu estou procurando, estou me sentindo como ele poderia ficar muito barulhento muito rápido para ter várias linhas de aliases, além de outros atributos.

Este último também trabalha, no entanto, ele gera o aviso do compilador CS3016 , e diz que essa abordagem não é compatível com CLS. Obviamente, isso não necessariamente impedir-me de ainda usá-lo, mas eu aprendi a sempre avisos tratar como erros.

A minha pergunta real é que eu deveria ignorar minhas objeções com duplicatas e apenas ir em frente e usá-los, ou se há alguma outra solução que poderia ser usado?

Obrigado.

Foi útil?

Solução

Pessoalmente eu gostaria de ir com a abordagem AllowMultiple: Eu não acho que o "ruído" vai ser muito de um problema a menos que você realmente tem caminhões de identificadores para cada comando. Mas se você não gosta disso e quer ficar compatível com CLS, uma outra solução seria fornecer construtores sobrecarregados para AdditionalIdentifierAttribute:

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

A desvantagem é que isto faz limitá-lo a um número predeterminado de identificadores.

Dito isso, o cumprimento CLS é realmente apenas uma consideração importante se você está construindo uma biblioteca que outros são propensos a usar (e especificamente de outras línguas). Se este tipo ou a biblioteca é interno à sua aplicação, então é razoável ignorar os avisos de conformidade CLS.

EDIT: Pensar mais sobre isso, você tem um monte de atributos sobre esses enums. Você pode querer considerar a criação de uma classe de comando abstrato em vez disso, e expondo o identificadores, uso, etc. como propriedades dessa classe; então derivar tipos concretos de comando que retornam os valores apropriados a partir dessas propriedades. Este potencialmente também permite que você mover a lógica de tratamento para aqueles Comando objetos em vez de ligar o valor de enumeração.

Outras dicas

Você também pode usar "params string [] aliases" no construtor para permitir uma lista de argumentos variável:

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

    public string[] allowedAliases { get; set; }

}

Isso permitiria que você faça:

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

Por que não ter um único atributo com várias propriedades? Têm a propriedade para o alias dar uma lista separada por vírgulas. Esta é a abordagem que tomar MVC para coisas como o AuthorizeAttribute para Roles. Internamente, a propriedade analisa a cadeia em uma matriz para facilidade de uso na classe atributo, mas permite-lhe uma maneira fácil de configurar a sua configuração.

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();
         }
    }
}

Em seguida, usá-lo como:

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

     ...
}

No entanto, outra abordagem seria a de ter o atributo tomar uma matriz de strings como um parâmetro de construtor - de que maneira, você começa o compilador para analisar a matriz para você (à custa de um pouco mais de goop ao aplicar o atributo) assim :

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

Uma rápida 'n exemplo suja de implementar e usar tais uma técnica parecida com esta:

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 em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top