Вопрос

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

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

Пример:

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

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

    // ...
}

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

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

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

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

Спасибо.

Это было полезно?

Решение

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

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

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

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

Редактировать: Размышляя дальше об этом, у вас есть довольно много атрибутов в этих перечислениях.Возможно, вы захотите вместо этого создать абстрактный командный класс и предоставить информацию об идентификаторах, использовании и т.д.как свойства этого класса;затем выведите конкретные типы команд, которые возвращают соответствующие значения из этих свойств.Потенциально это также позволяет вам переместить логику обработки в эти командные объекты вместо включения значения enum.

Другие советы

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

[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)

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

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,

     ...
}

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

[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);
            }
        }
    }
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top