我正在C#中创建一个网络聊天客户端作为辅助项目。除了简单的文本消息,我还有可以输入到输入TextBox的斜杠前缀命令。我使用模块化方法创建一个包含所有各种命令的枚举,然后用属性装饰这些命令。

这些属性指定可以输入什么slash-prefixed命令来触发命令,以及主命令标识符和命令用法的任何别名。

示例:

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。显然,这并不一定会阻止我继续使用它,但我已经学会了将警告视为错误。

我的实际问题是,我是否应该忽略我对重复的反对意见并继续使用它们,或者是否有其他可以使用的解决方案?

谢谢。

有帮助吗?

解决方案

就个人而言,我会采用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,从那些属性返回适当的值。这可能还允许您将处理逻辑移动到那些Command对象中,而不是打开枚举值。

其他提示

你也可以使用“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 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,

     ...
}

另一种方法是让属性将一个字符串数组作为构造函数参数 - 这样,你就可以让编译器为你解析数组(在应用属性时以更多的goop为代价) :

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

实施&amp; amp;的一个简单的例子使用这种技术看起来像这样:

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