2009-10-21 29 views
1

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

属性指定可以输入什么斜线前缀的命令来触发命令,以及到主命令标识符和命令的使用任何别名。

实施例:当我尝试以允许多个别名到主命令

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

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

    // ... 
} 

我的问题出现了。我尝试过这两种方法:允许重复AdditionalIdentifier属性,或者通过在AdditionalIdentifier中设置构造函数参数params string[]

与前者一样,我通过装饰属性类AttributeUsage并将AllowMultiple设置为true来实现它。虽然这的确能够达到我所期望的效果,但我觉得,除了其他属性之外,它可能会非常快地产生几行别名。

后者也适用,但是,它所产生的compiler warning CS3016,并说这种做法是不符合CLS。显然,这并不一定会阻止我继续使用它,但我已经学会了将警告视为错误。

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

谢谢。

回答

1

个人而言,我会去的方法的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对象中,而不是打开枚举值。

+0

我想你是对的。另一种方法将是您的多构造函数方法,并同时使用AllowMultiple,从而实现更大的灵活性。谢谢! – mgbowen 2009-10-21 22:08:32

2

为什么不能有一个具有多个属性的属性?让别名的属性采用逗号分隔的列表。这是他们在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, 

    ... 
} 
+0

谢谢你提出这个建议,我完全忘记了这种可能性!这应该减少类和装饰的数量:)。如果重复的次数确实会成为问题,我想我会使用这种方法。 – mgbowen 2009-10-21 22:10:35

0

另一种方法是将有属性需要字符串作为构造函数的参数数组 - 这样,你得到的编译器解析数组你(在多一点GOOP为代价施加时的属性),因此:

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

使用这样的技术看起来像实施&的快速“N脏示例这样的:

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

你也可以使用 “PARAMS字符串[]别名” 在构造函数中,使变量参数列表:

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

+1比我的漂亮! – 2009-10-21 22:47:04