私は属性が非常に役に立つことを知っています。プロパティタブでプロパティを隠すことができる[Browsable(false)]
のようないくつかの定義済みのものがあります。これが属性を説明する良い質問です。 .NETの属性とは何ですか?
プロジェクトで実際に使用している定義済みの属性(およびそれらの名前空間)は何ですか?
[DebuggerDisplay]
は、デバッグ中にTypeのインスタンスの上にマウスを移動したときに、Typeのカスタマイズされた出力を素早く確認するのに非常に役立ちます。例:
[DebuggerDisplay("FirstName={FirstName}, LastName={LastName}")]
class Customer
{
public string FirstName;
public string LastName;
}
これはデバッガの中でどのように見えるべきかです:
また、CacheDuration
プロパティを設定した[WebMethod]
属性を使用すると、Webサービスメソッドが不必要に実行されるのを防ぐことができます。
System.Obsolete
は、私の意見では、フレームワークで最も有用な属性の1つです。使用されなくなったコードについて警告を発する機能は非常に便利です。私は開発者に何かが使われてはいけないことを伝える方法があること、そしてその理由を説明し、より良い/新しい方法で何かを指摘する方法があるのが大好きです。
Conditional attribute
はデバッグにも非常に便利です。リリース用にソリューションをビルドしてもコンパイルされないデバッグ目的でコードにメソッドを追加できます。
それから私が役に立つと思うWebコントロールに特有の多くの属性がありますが、それらはより特定的であり、私が見つけたものからサーバーコントロールの開発以外の用途はありません。
[Flags]
はかなり便利です。構文糖は確かに、それでもかなりいいです。
[Flags]
enum SandwichStuff
{
Cheese = 1,
Pickles = 2,
Chips = 4,
Ham = 8,
Eggs = 16,
PeanutButter = 32,
Jam = 64
};
public Sandwich MakeSandwich(SandwichStuff stuff)
{
Console.WriteLine(stuff.ToString());
// ...
}
// ...
MakeSandwich(SandwichStuff.Cheese
| SandwichStuff.Ham
| SandwichStuff.PeanutButter);
// produces console output: "Cheese, Ham, PeanutButter"
Leppieは私が気付いていなかったことを指摘しています。そしてそれはむしろこの属性に対する私の熱意を弱めています:not列挙型変数の有効な値としてビットの組み合わせを許可するようにコンパイラーに指示します。コンパイラーはこれに関係なく、列挙型に対してこれを許可します。私のC++の背景は透けて見えます...ため息
私はSystem.Diagnosticsの [DebuggerStepThrough]
が好きです。
1行のdo-nothingメソッドやプロパティへのステップインを回避するのに非常に便利です(自動プロパティなしで初期の.NETで作業することを余儀なくされている場合)。短いメソッドまたはプロパティの取得メソッドまたは設定メソッドに属性を設定すると、デバッガで「step into」をクリックしたときでもすぐに飛ぶことができます。
それが価値があるものについては、これが すべての.NET属性のリストです 。数百あります。
私は他の誰かについては知りませんが、やるべき深刻なRTFMがあります。
私の投票は[Conditional]
に対するものです
[Conditional("DEBUG")]
public void DebugOnlyFunction()
{
// your code here
}
これを使用して、高度なデバッグ機能を持つ機能を追加できます。 Debug.Write
と同様に、これはデバッグビルドでのみ呼び出されるため、複雑なデバッグロジックをプログラムのメインフローの外側にカプセル化することができます。
私は、DisplayName
、Description
、およびDefaultValue
属性を、ユーザーコントロール、カスタムコントロール、またはプロパティグリッドを介して編集するクラスのパブリックプロパティよりも常に使用します。これらのタグは、名前、説明パネル、およびデフォルト値に設定されていない太字の値をフォーマットするために.NET PropertyGridによって使用されます。
[DisplayName("Error color")]
[Description("The color used on nodes containing errors.")]
[DefaultValue(Color.Red)]
public Color ErrorColor
{
...
}
XMLコメントが見つからない場合は、Visual StudioのIntelliSenseでDescription
属性が考慮されるようにしてください。同じ文を2回繰り返す必要がなくなります。
[Serializable]
は、xmlなどの外部データソースまたはリモートサーバーとの間でオブジェクトをシリアル化およびシリアル化解除するために常に使用されます。 それについての詳細はこちら
Hofstadtianの精神では、[Attribute]
属性は非常に便利です。なぜなら、それはあなたがあなた自身の属性を作成する方法だからです。私はプラグインシステムの実装、Enumへの説明の追加、複数のディスパッチや他のトリックをシミュレートするためにインターフェースの代わりに属性を使用しました。
ここで はおもしろい属性 InternalsVisibleTo についての投稿です。基本的には、C++の友達が機能にアクセスするのと似ています。ユニットテストにはとても便利です。
私は [DefaultValue]
が非常に役に立つことがわかりました。
nUnit ライブラリから、[TestFixture]
と[Test]
を提案します。
コード内のユニットテストは、リファクタリングおよび体系化されたドキュメントの安全性を提供します。
これは、フレームワークでは適切な名前でもサポートもされていないため、パラメータを必要としませんが、この属性は不変クラスの有用なマーカーです。
[ImmutableObject(true)]
私は[ThreadStatic]
属性をスレッドとスタックベースのプログラミングと組み合わせて使うのが好きです。たとえば、呼び出しシーケンスの残りの部分と共有したい値が欲しいが、帯域外(つまり呼び出しパラメータの外側)でそれを行いたい場合は、次のようにします。
class MyContextInformation : IDisposable {
[ThreadStatic] private static MyContextInformation current;
public static MyContextInformation Current {
get { return current; }
}
private MyContextInformation previous;
public MyContextInformation(Object myData) {
this.myData = myData;
previous = current;
current = this;
}
public void Dispose() {
current = previous;
}
}
私のコードの後半では、これを使用して、私のコードの下流にいる人々に帯域外のコンテキスト情報を提供できます。例:
using(new MyContextInformation(someInfoInContext)) {
...
}
ThreadStatic属性を使用すると、問題のスレッドにのみ呼び出しをスコープ設定でき、スレッド間でのデータアクセスという面倒な問題を回避できます。
[XmlIgnore]
これにより、保存時に例外が発生する可能性のある 'parent'オブジェクトを(任意のxmlシリアル化で)無視することができます。
DebuggerHiddenAttribute これは、デバッグすべきでないコードへのステップインを回避することを可能にします。
public static class CustomDebug
{
[DebuggerHidden]
public static void Assert(Boolean condition, Func<Exception> exceptionCreator) { ... }
}
...
// The following assert fails, and because of the attribute the exception is shown at this line
// Isn't affecting the stack trace
CustomDebug.Assert(false, () => new Exception());
また、スタックトレースでメソッドを表示しないようにします。他のメソッドをラップするメソッドがある場合に役立ちます。
[DebuggerHidden]
public Element GetElementAt(Vector2 position)
{
return GetElementAt(position.X, position.Y);
}
public Element GetElementAt(Single x, Single y) { ... }
ここでGetElementAt(new Vector2(10, 10))
を呼び出し、ラップされたメソッドでエラーが発生した場合、呼び出しスタックはエラーをスローするメソッドを呼び出しているメソッドを表示していません。
DesignerSerializationVisibilityAttribute
はとても便利です。ランタイムプロパティをコントロールまたはコンポーネントに配置し、デザイナーにそれをシリアル化させたくない場合は、次のように使用します。
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public Foo Bar {
get { return baz; }
set { baz = value; }
}
ほんの少しの属性だけがコンパイラサポートを得ますが、AOPには非常に興味深い使い方があります。 PostSharp はメソッドにILを注入するためにあなたのオーダーメイドの属性を使います。些細な例であるトレース - しかし他のいくつかの良い例は自動INotifyPropertyChanged実装のようなものです(ここで)。
いくつか発生し、コンパイラまたはランタイムに直接影響します。
[Conditional("FOO")]
- このメソッドの呼び出し(引数の評価を含む)は、ビルド中に "FOO"シンボルが定義されている場合にのみ行われます。[MethodImpl(...)]
- 同期、インライン展開などのいくつかのことを示すために使用されます[PrincipalPermission(...)]
- セキュリティチェックをコードに自動的に挿入するために使用されます[TypeForwardedTo(...)]
- 呼び出し元を再構築せずにアセンブリ間で型を移動するために使用されますリフレクションを使って手動でチェックされるもの - 私はSystem.ComponentModel
属性が大好きです。 [TypeDescriptionProvider(...)]
、[TypeConverter(...)]
、[Editor(...)]
のようなもので、データバインディングのシナリオにおける型の振る舞いを完全に変えることができます(動的プロパティなど)。
私は最近[DataObjectMethod]
を使っています。このメソッドについて説明しているので、ObjectDataSource(または他のコントロール)と共に自分のクラスを使用できます。
[DataObjectMethod(DataObjectMethodType.Select)]
[DataObjectMethod(DataObjectMethodType.Delete)]
[DataObjectMethod(DataObjectMethodType.Update)]
[DataObjectMethod(DataObjectMethodType.Insert)]
コードカバレッジクロールを実行するとすれば、この2つが一番上だと思います。
[Serializable]
[WebMethod]
[TypeConverter(typeof(ExpandableObjectConverter))]
(あなたのコントロールの)クラスであるプロパティを拡張するようにデザイナーに伝えます
[Obfuscation]
アセンブリ、タイプ、またはメンバーに対して指定されたアクションを実行するように難読化ツールに指示します。 (通常はアセンブリレベル[Assembly:ObfuscateAssemblyAttribute(true)]
を使用します)
プロジェクトがソリューションに含まれていない場合、[EditorBrowsable(EditorBrowsableState.Never)]
を使用すると、IntelliSenseからプロパティとメソッドを隠すことができます。流暢なインターフェースに対して無効なフローを隠すのに非常に役立ちます。どのくらいの頻度でGetHashCode()またはEquals()を使用しますか?
MVCの場合、[ActionName("Name")]
は、同じメソッドシグネチャを持つGetアクションとPostアクションを持つこと、またはアクション名にダッシュを使用することを可能にします。
私が好きな中間層開発者になる
System.ComponentModel.EditorBrowsableAttribute
UI開発者が見る必要のないプロパティに圧倒されないようにプロパティを隠すことができます。
System.ComponentModel.BindableAttribute
データバインドする必要がないものもあります。繰り返しますが、UI開発者が行う必要がある作業が少なくなります。
私はローレンス・ジョンストンが述べたDefaultValue
も好きです。
System.ComponentModel.BrowsableAttribute
とFlags
は定期的に使われます。
必要に応じてSystem.STAThreadAttribute System.ThreadStaticAttribute
を使います。
ところで。私はこれらすべての.Netフレームワーク開発者にとっても同様に価値があります。
私が最もよく使用する属性はXMLシリアライゼーションに関連したものです。
XmlRoot
XmlElement
XmlAttribute
等...
迅速で汚いXMLの構文解析や直列化を行うときに非常に役立ちます。
以下の属性も非常に重要であることをここで言及することが重要です。
STAThreadAttribute
アプリケーションのCOMスレッドモデルがシングルスレッドアパートメント(STA)であることを示します。
たとえば、この属性はWindowsフォームアプリケーションで使用されます。
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
そしてまた….
SuppressMessageAttribute
特定の静的分析ツールのルール違反の報告を抑制し、単一のコード成果物に対する複数の抑制を許可します。
例えば:
[SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "isChecked")]
[SuppressMessage("Microsoft.Performance", "CA1804:RemoveUnusedLocals", MessageId = "fileIdentifier")]
static void FileNode(string name, bool isChecked)
{
string fileIdentifier = name;
string fileName = name;
string version = String.Empty;
}
私の頭の上に、ここに私が実際に大規模プロジェクト(〜500k LoC)で使用する事前定義された属性の使用頻度によって大まかに分類されたクイックリストがあります:
フラグ、直列化可能、Webメソッド、COMVisible、TypeConverter、条件付き、ThreadStatic、廃止、InternalsVisibleTo、DebuggerStepThrough。
[DeploymentItem("myFile1.txt")]
MSDN Doc on DeploymentItem
これは、ファイルに対してテストしている場合、またはファイルをテストへの入力として使用している場合には非常に便利です。
CodeSmithを介してデータエンティティクラスを生成し、検証ルーチンに属性を使用します。これが一例です。
/// <summary>
/// Firm ID
/// </summary>
[ChineseDescription("送样单位编号")]
[ValidRequired()]
public string FirmGUID
{
get { return _firmGUID; }
set { _firmGUID = value; }
}
そしてデータエンティティクラスに付けられた属性に基づいて検証を行うためのユーティリティクラスを得ました。これがコードです:
namespace Reform.Water.Business.Common
{
/// <summary>
/// Validation Utility
/// </summary>
public static class ValidationUtility
{
/// <summary>
/// Data entity validation
/// </summary>
/// <param name="data">Data entity object</param>
/// <returns>return true if the object is valid, otherwise return false</returns>
public static bool Validate(object data)
{
bool result = true;
PropertyInfo[] properties = data.GetType().GetProperties();
foreach (PropertyInfo p in properties)
{
//Length validatioin
Attribute attribute = Attribute.GetCustomAttribute(p,typeof(ValidLengthAttribute), false);
if (attribute != null)
{
ValidLengthAttribute validLengthAttribute = attribute as ValidLengthAttribute;
if (validLengthAttribute != null)
{
int maxLength = validLengthAttribute.MaxLength;
int minLength = validLengthAttribute.MinLength;
string stringValue = p.GetValue(data, null).ToString();
if (stringValue.Length < minLength || stringValue.Length > maxLength)
{
return false;
}
}
}
//Range validation
attribute = Attribute.GetCustomAttribute(p,typeof(ValidRangeAttribute), false);
if (attribute != null)
{
ValidRangeAttribute validRangeAttribute = attribute as ValidRangeAttribute;
if (validRangeAttribute != null)
{
decimal maxValue = decimal.MaxValue;
decimal minValue = decimal.MinValue;
decimal.TryParse(validRangeAttribute.MaxValueString, out maxValue);
decimal.TryParse(validRangeAttribute.MinValueString, out minValue);
decimal decimalValue = 0;
decimal.TryParse(p.GetValue(data, null).ToString(), out decimalValue);
if (decimalValue < minValue || decimalValue > maxValue)
{
return false;
}
}
}
//Regex validation
attribute = Attribute.GetCustomAttribute(p,typeof(ValidRegExAttribute), false);
if (attribute != null)
{
ValidRegExAttribute validRegExAttribute = attribute as ValidRegExAttribute;
if (validRegExAttribute != null)
{
string objectStringValue = p.GetValue(data, null).ToString();
string regExString = validRegExAttribute.RegExString;
Regex regEx = new Regex(regExString);
if (regEx.Match(objectStringValue) == null)
{
return false;
}
}
}
//Required field validation
attribute = Attribute.GetCustomAttribute(p,typeof(ValidRequiredAttribute), false);
if (attribute != null)
{
ValidRequiredAttribute validRequiredAttribute = attribute as ValidRequiredAttribute;
if (validRequiredAttribute != null)
{
object requiredPropertyValue = p.GetValue(data, null);
if (requiredPropertyValue == null || string.IsNullOrEmpty(requiredPropertyValue.ToString()))
{
return false;
}
}
}
}
return result;
}
}
}
[System.Security.Permissions.PermissionSetAttribute]
を使用すると、宣言型セキュリティを使用してPermissionSetのセキュリティアクションをコードに適用できます。
// usage:
public class FullConditionUITypeEditor : UITypeEditor
{
// The immediate caller is required to have been granted the FullTrust permission.
[PermissionSetAttribute(SecurityAction.LinkDemand, Name = "FullTrust")]
public FullConditionUITypeEditor() { }
}
// on configuration sections
[ConfigurationProperty]
// in asp.net
[NotifyParentProperty(true)]
私はいつも属性[Serializable]
、[WebMethod]
、[DefaultValue]
、[Description("description here")]
を使います。
しかしそれ以外にもc#に グローバル属性 があります。
[Assembly: System.CLSCompliant(true)]
[Assembly: AssemblyCulture("")]
[Assembly: AssemblyDescription("")]