質問
C#でサイドプロジェクトとしてネットワークチャットクライアントを作成しています。単純なテキストメッセージに加えて、入力TextBoxに入力できるスラッシュで始まるコマンドもあります。さまざまなコマンドをすべて含む列挙型を作成し、それらのコマンドを属性で装飾することにより、モジュラーアプローチを使用しました。
属性は、コマンドをトリガーするために入力できるスラッシュ付きコマンド、およびプライマリコマンド識別子とコマンドの使用法のエイリアスを指定します。
例:
public enum CommandType : byte
{
[PrimaryIdentifier("file"),
AdditionalIdentifier("f"),
CommandUsage("[<recipient>] [<filelocation>]")]
FileTransferInitiation,
[PrimaryIdentifier("accept"),
AdditionalIdentifier("a")]
AcceptFileTransfer,
// ...
}
プライマリコマンドに複数のエイリアスを許可しようとすると、問題が発生します。この2つの方法を試しました。 AdditionalIdentifier
属性の複製を許可するか、 AdditionalIdentifier
のコンストラクター引数を 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オブジェクトに移動できる可能性もあります。
他のヒント
&quot; params string [] aliases&quot;も使用できます。コンストラクターで変数引数リストを許可します:
[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)
複数のプロパティを持つ単一の属性がないのはなぜですか?エイリアスのプロパティにコンマ区切りのリストを使用させます。これは、ロールのAuthorizeAttributeなどのMVCでのアプローチです。内部的には、プロパティは文字列を配列に解析して属性クラスで使いやすくしますが、設定を簡単に設定できます。
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"})]
&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);
}
}
}
}