Атрибуты C # - массивы или дубликаты? - PullRequest
1 голос
/ 22 октября 2009

Я создаю клиент сетевого чата в C # как побочный проект. В дополнение к простым текстовым сообщениям, у меня также есть команды с префиксом, которые можно вводить в поле ввода TextBox. Я использовал модульный подход, создав перечисление, содержащее все различные команды, и затем украсив эти команды атрибутами.

Атрибуты указывают, какая команда с префиксом косая черта может быть введена для запуска команды, а также любые псевдонимы к первичному идентификатору команды и ее использованию.

Пример:

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

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

    // ...
}

Моя проблема возникает, когда я пытаюсь разрешить несколько псевдонимов для основной команды. Я попытался сделать это двумя способами: разрешив дубликаты атрибута AdditionalIdentifier или указав аргумент конструктора в AdditionalIdentifier a params string[].

С первым я реализовал это, украсив класс атрибута AttributeUsage и установив AllowMultiple в true. Хотя это действительно дает то, что я ищу, я чувствую, что может быть очень шумно и очень быстро иметь несколько строк псевдонимов в дополнение к другим атрибутам.

Последний также работает, однако он генерирует предупреждение компилятора CS3016 и говорит, что этот подход не совместим с CLS. Очевидно, это не обязательно мешает мне продолжать его использовать, но я научился всегда воспринимать предупреждения как ошибки.

Мой настоящий вопрос: должен ли я игнорировать свои возражения с дубликатами и просто использовать их, или есть какое-то другое решение, которое можно использовать?

Спасибо.

Ответы [ 4 ]

2 голосов
/ 22 октября 2009

Вы также можете использовать «params string [] aliases» в конструкторе, чтобы разрешить список переменных аргументов:

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

    public string[] allowedAliases { get; set; }

}

Это позволит вам сделать:

[Test("test1", "test2", "test3")]
static void Main(string[] args)
1 голос
/ 22 октября 2009

Почему бы не иметь один атрибут с несколькими свойствами? Пусть свойство псевдонима будет разделено запятыми. Это подход, который они используют в MVC для таких вещей, как AuthorizeAttribute for Roles. Внутренне свойство анализирует строку в массив для простоты использования в классе атрибутов, но позволяет легко настроить вашу конфигурацию.

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

Тогда используйте это как:

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

     ...
}
1 голос
/ 22 октября 2009

Лично я бы пошел с подходом AllowMultiple: я не думаю, что "шум" будет такой большой проблемой, если у вас действительно нет загруженных идентификаторами для каждой команды. Но если вам это не нравится и вы хотите оставаться CLS-совместимым, еще одним решением будет предоставить перегруженные конструкторы для AdditionalIdentifierAttribute:

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

Недостатком является то, что это ограничивает вас заранее определенным количеством идентификаторов.

Тем не менее, соответствие CLS действительно является главным соображением, если вы создаете библиотеку, которую, вероятно, будут использовать другие (и в частности, из других языков). Если этот тип или библиотека являются внутренними для вашего приложения, то разумно игнорировать предупреждения о соответствии CLS.

РЕДАКТИРОВАТЬ: Если подумать об этом, у вас довольно много атрибутов в этих перечислениях. Возможно, вы захотите рассмотреть создание абстрактного класса Command вместо этого, и указание идентификаторов, использования и т. Д. В качестве свойств этого класса; затем получить конкретные типы команд, которые возвращают соответствующие значения из этих свойств. Это потенциально также позволяет вам перемещать логику обработки в эти объекты Command, а не включать значение enum.

0 голосов
/ 22 октября 2009

Еще один подход заключается в том, чтобы атрибут принимал массив строк в качестве параметра конструктора - таким образом, вы получаете компилятор для анализа массива за вас (за счет небольшого увеличения цикла при применении атрибута) :

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

Быстрый и грязный пример реализации и использования такой техники выглядит следующим образом:

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);
            }
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...