最有用的属性


784

我知道属性非常有用。有一些预定义的[Browsable(false)]属性,例如允许您在属性选项卡中隐藏属性。这是一个解释属性的好问题:.NET中的属性是什么?

您在项目中实际使用的预定义属性(及其名称空间)是什么?


27
这是什么问题?,整个页面上充斥着精美的答案和精彩的解释。在阅读本文的过程中,我获得了像采访许多专家这样的观点的经验。+100。
Muthu Ganapathy Nathan,

我同意,像这样的问题是一些最有价值的问题-使SO的用处不大,以至于无法解决。
David Thielen

Answers:


669

[DebuggerDisplay]在调试期间将鼠标悬停在Type实例上时,对于快速查看Type的自定义输出很有帮助。例:

[DebuggerDisplay("FirstName={FirstName}, LastName={LastName}")]
class Customer
{
    public string FirstName;
    public string LastName;
}

这是它在调试器中的外观:

alt text

另外,值得一提的是,[WebMethod]具有CacheDuration属性集的属性可以避免不必要地执行Web服务方法。


62
哇,真是太好了。我通常通过覆盖ToString完成相同的操作,但这更好。
布赖恩

17
请注意这一点,它比ToString占用了CPU更大的内存。
NikolaRadosavljević

1
您也可以使用它来显示方法的结果。如果方法(或属性获取)有副作用,则可能会带来令人困惑的调试体验。
岛之风Skaar

4
@NikolaRadosavljević是否只会在调试过程中占用CPU功率
Nickolay Kondratyev

2
@Nickolay Kondratyev:我并不了解所有的来龙去脉,但是您可以看看以下Web服务最佳实践,这些最佳实践可以带给您一些结论:blogs.msdn.com/b/jaredpar/archive/2011/03/ 18 /…
NikolaRadosavljević13年

273

System.Obsolete我认为,它是框架中最有用的属性之一。发出有关不应再使用的代码的警告的功能非常有用。我喜欢有一种方法可以告诉开发人员不再使用某些东西,并且有一种方法可以解释原因并指出更好/新的方法。

Conditional attribute对于调试使用也非常方便。它允许您在代码中添加用于调试目的的方法,这些方法在构建要发布的解决方案时不会被编译。

然后,我发现许多特定于Web控件的属性很有用,但是这些属性更加具体,在我发现的服务器控件开发之外没有任何用途。


50
您可以将“ true”作为参数之一传递给System.Obsolete,这将导致警告变为错误,从而破坏构建。显然,一旦清除了所有警告,就应该这样做。:)
阿德里安·克拉克

14
清除所有警告后,仅删除该方法会更好吗?
佩德罗(Pedro)

10
@Pedro:有时由于向后兼容的原因而不能。如果它是私有的且未使用,是的,请将其删除。
Fantius

3
@plinth引发异常将是一个坏主意,原因有很多,第一点是,使用Obsolete()的主要原因是为了使您可以在过渡阶段保持编译后的代码正常工作。如果您不允许任何人调用该方法,为什么不删除它呢?
丹·赫伯特

17
@plinth是为了防止代码使用该方法。如果将方法标记为过时,旧代码将保持二进制兼容,但是如果引发异常,它将停止工作。如果有人使用反射来绕过“过时”标志,那么您会遇到更严重的问题……
Dan Herbert

204

[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指出了一些我尚未意识到的事情,但这削弱了我对该属性的热情:它没有指示编译器允许将位组合作为枚举变量的有效值,而编译器无论如何都允许这样做。我的C ++背景显示通过......


那么Flags属性到底能做什么?
AndreiRînea,

13
我希望你们认识到Flags属性确实使人烦恼。除了TypeConverter之外,根本不需要/使用它。
嬉皮

3
@leppie:也是ToString()。但是...哇 由于某种原因,我一直期望没有该属性的枚举的行为与C ++相同:或值产生一个整数(不能原样传递给期望枚举参数的方法)。我现在知道情况并非如此。弱...好吧,.NET枚举很烂。
Shog9

2
[Flags]实际上仅帮助调试器和.ToString()函数知道一个值可能是枚举中多个声明的组合。我不确定,它可能也会使Intellisense帮助您更有效地使用枚举。
Kenzi 2012年

31
[Flags]确实比仅仅使用语法糖有更多用途。使用Web服务时,如果SandwichStuff.Cheese | SandwichStuff.Ham | SandwichStuff.Jam传递类似的值,则序列化/反序列化将不起作用。如果没有该[Flags]属性,则反序列化器将不知道该值可以是标志的组合。在花了大约两天时间思考为什么我的WCF不能正常工作之后,才以辛苦的方式学习了此方法。
Anchit

177

我喜欢[DebuggerStepThrough]来自System.Diagnostics

避免单步执行这些单行操作方法或属性(如果您被迫在没有自动属性的早期.Net中工作),这非常方便。将属性放在短方法或属性的获取器或设置器上,即使在调试器中单击“ step into”,您也可以正常运行。


5
我希望我知道很多次,这让我
感到震惊

1
令人遗憾的是,它被闭包打破了- 有关更多信息,请参阅gregbeech.com/blogs/tech/archive/2008/10/17/…
格雷格·比奇

3
对您知道的任何WM_Paint代码也有用:)
Pondidum,

@GregBeech该URL返回一个.NET错误。优!:)
smdrager 2012年

@smdrager-一定是一个临时性问题,今天似乎对我有用。
格雷格·比奇

135

对于它的价值,这里是所有.NET属性的列表。有几百个。

我不认识其他任何人,但是我有一些严肃的RTFM要做!


33
发布的列表适用于.net 1.1,这是3.5 msdn.microsoft.com/zh-cn/library/system.attribute.aspx的列表(您必须向下滚动一点)
kay.one

2
更新了问题中的链接。现在它是3.5的完整列表
R. Martinho Fernandes

8
实际上,它链接到最新版本,而不是3.5版本。
Brian Ortiz 2010年

1
现在,如果不仅列表不仅仅是链接列表,还包括名称和描述。那好吧。@BrianOrtiz是正确的。该列表的版本为4.5。
发光

您只需在顶部标有“其他版本”的位置更改目标框架即可。
Novaterata,2015年

129

我的投票是 Conditional

[Conditional("DEBUG")]
public void DebugOnlyFunction()
{
    // your code here
}

您可以使用它来添加具有高级调试功能的功能。像一样Debug.Write,它仅在调试版本中被调用,因此允许您将复杂的调试逻辑封装在程序的主要流程之外。


5
这与执行#if DEBUG一样吗?
尼尔N

10
某种程度上,#if DEBUG表示调用方也不必调用它,而Conditioinal则退出该调用,但使其成为在JIT时消除的NOP。
Rangoric 2011年

23
另外,通常在调用周围使用#if DEBUG ,在方法周围使用[Conditional] 。所以,如果你调用调试方法的100倍,关闭它是一个单一的代码更改的问题,而不是100
史蒂夫库珀

13
Rangoric的评论是微妙的错误(至少对于C#是这样):方法未修改就包含在内;呼叫站点本身被省略。这有一些含义:不评估参数,并且在编译器的输出中包含未经修改的条件方法。您可以通过反射来验证。 msdn.microsoft.com/en-us/library/aa664622.aspx blogs.msdn.com/b/jmstall/archive/2007/10/15/...
马克Sowul

97

我总是用DisplayNameDescriptionDefaultValue属性在我的用户控件,自定义控件,不然我会通过属性编辑网格中任何一类的公共属性。.NET PropertyGrid使用这些标记来格式化名称,描述面板和未设置为默认值的粗体值。

[DisplayName("Error color")]
[Description("The color used on nodes containing errors.")]
[DefaultValue(Color.Red)]
public Color ErrorColor
{
    ...
} 

我只是希望Description如果找不到XML注释,Visual Studio的IntelliSense将考虑该属性。这样可以避免重复相同的句子两次。


3
不能相信没有指出Description与枚举使用时,直到你..它是最有帮助的我..
nawfal

68

[Serializable]一直使用来与外部数据源(例如xml)或远程服务器之间的对象进行序列化和反序列化。在这里了解更多。


它实际上是指psuedoattribute,因为C#会为[Serializable]而不是自定义属性实例发出元数据标志;)
TraumaPony

1
尽管[Serializable]非常有用,但远非完美。要获得所需的结果,需要太多的修补和反复试验。
shoosh

我将秒杀!
John Bubriski

如果要对自动序列化进行更多控制,则System.NonSerializedAttribute很有用。
CSharper

附带说明一下,我要补充一点,内置.Net序列化的性能非常差,比手工编写的代码慢2到3个数量级。
redcalx 2010年

57

按照霍夫施塔特精神,[Attribute]属性是非常有用的,因为这是您创建自己的属性的方式。我使用属性而不是接口来实现插件系统,向Enums添加描述,模拟多个调度和其他技巧。


13
听起来不错!您介意展示一些插件系统示例和枚举说明吗?这些都是我对实现自己感兴趣的东西!
John Bubriski

46

是有关有趣的属性InternalsVisibleTo的帖子。基本上,它的作用是模仿C ++朋友的访问功能。它非常方便进行单元测试。


7
您难道不擅长针对无法/不应进行测试的内容进行单元测试吗?
the_drow

@the_drow:您谈论的是“私有访问者”:msdn.microsoft.com/en-us/library/ms184807%28v=vs.80%29.aspx
habakuk 2012年

@habakuk:不是。在某些情况下,通常由于设计不良而应公开内部类以进行单元测试。
the_drow

2
@the_drow:我不会说InternalsVisibleTo对于单元测试是有害的;您可以创建和测试在项目外部不可见的较小“单元”(这有助于您使用干净的小型api)。但是,如果您需要“私有访问者”进行单元测试,则可能出了点问题。
habakuk 2012年

10
@the_drow我不同意您的internal公开声明。它在要测试的程序集中是公开的,应该进行单元测试,以便程序集中的其他类可以假定它具有更正功能。如果不对它进行单元测试,则必须在所有使用类中测试其功能。
tvanfosson 2012年


28

我建议[TestFixture][Test]-从NUnit的库。

代码中的单元测试在重构和整理文档时提供了安全性。


26
[XmlIgnore]

因为这允许您忽略(在任何xml序列化中)“父”对象,否则这些对象在保存时会导致异常。


25

它没有很好的命名,在框架中没有很好的支持,并且不需要参数,但是此属性是不可变类的有用标记:

[ImmutableObject(true)]

6
根据文档,仅在设计时使用(不幸的是)。
汉斯·基辛2009年

1
鉴于这仅是设计时,也许最好创建自己的ImmutableObjectAttribute类-至少可以消除该参数。
罗伊·廷克

25

我喜欢将[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属性使我可以将调用的作用域仅限制在有问题的线程上,从而避免了跨线程访问数据的麻烦问题。


以及如何访问呢?在这里不了解您的用法示例的重点。你可以解释吗?
2015年

@Beachwalker Current应该是静态的,现在进行编辑。现在,您可以访问MyContextInformation.Current以获取堆栈上的活动上下文。在某些情况下,这是一个非常好的概念,我们(我的公司)引擎将其用于许多目的。
Felix K.

23

所述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))并且包装方法发生错误,则调用堆栈未显示正在调用引发错误的方法的方法。


21

DesignerSerializationVisibilityAttribute非常有用 当您在控件或组件上放置运行时属性时,如果您不希望设计人员对其进行序列化,则可以按以下方式使用它:

[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public Foo Bar {
    get { return baz; }
    set { baz = value; }
}

4
对于WinForms组件非常有用。与[Browsable(false)]结合使用
Mark Heath 2010年

3
重点- [Browsable(false)]必须将其隐藏在设计者的用户面前,而这[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]是必需的,这样它就不会序列化。
配置器

17

只有少数属性获得编译器支持,但是AOP中非常有趣的使用属性:PostSharp使用定制的属性将IL注入方法中,从而允许所有方式的能力... log / trace是简单的示例-但还有其他一些很好的示例是类似自动INotifyPropertyChanged实现(在这里)。

发生并直接影响编译器或运行时的一些事件:

  • [Conditional("FOO")] -仅在构建期间定义了“ FOO”符号的情况下,才会调用此方法(包括参数评估)
  • [MethodImpl(...)] -用于指示一些事情,例如同步,内联
  • [PrincipalPermission(...)] -用于将安全检查自动注入代码中
  • [TypeForwardedTo(...)]-用于在程序集之间移动类型而不重建调用方

对于通过反射手动检查的事情-我是System.ComponentModel属性的忠实拥护者;东西喜欢[TypeDescriptionProvider(...)][TypeConverter(...)][Editor(...)]其可完全改变在数据绑定方案(即动态特性等)的类型的行为。


15

如果我要进行代码覆盖率爬网,我认为这两个将是最高的:

 [Serializable]
 [WebMethod]

15
[WebMethod]用于装饰Web服务中公开的方法。[可序列化]标记您的对象,以便可以将它们进行序列化,例如在应用程序域之间传递它们。
Kev

15

我一直在使用 [DataObjectMethod]最近。它描述了该方法,因此您可以将您的类与ObjectDataSource(或其他控件)一起使用。

[DataObjectMethod(DataObjectMethodType.Select)] 
[DataObjectMethod(DataObjectMethodType.Delete)] 
[DataObjectMethod(DataObjectMethodType.Update)] 
[DataObjectMethod(DataObjectMethodType.Insert)] 

更多信息


12

在当前项目中,我们使用

[ComVisible(false)]

它控制单个托管类型或成员,或程序集中所有类型对COM的可访问性。

更多信息


12
[TypeConverter(typeof(ExpandableObjectConverter))]

告诉设计器扩展属于(您控制的)类的属性

[Obfuscation]

指示混淆工具对程序集,类型或成员采取指定的操作。(尽管通常您使用的是程序集级别[assembly:ObfuscateAssemblyAttribute(true)]


1
我确实猜到了,但是错了。“混淆”属性仅是对第三方混淆者的提示。默认情况下,它不会导致编译器混淆任何内容。
Dan在火光旁摆弄2012年

@DanNeely对Visual Studio Pro / Ultimate用户免费!
克里斯·S

4
如果您指的是DotFuscator社区版,那么所提供的保护级别太低,至多它几乎没有任何价值。
Dan在火光中摆弄

@ricovox我添加了一个摘要
Chris S

9

我最常使用的属性是与XML序列化相关的属性。

XmlRoot

XmlElement

XmlAttribute

等等...

在进行任何快速而肮脏的XML解析或序列化时非常有用。


8

作为我喜欢的中层开发人员

System.ComponentModel.EditorBrowsableAttribute 让我隐藏属性,以便UI开发人员不会被他们不需要看到的属性所淹没。

System.ComponentModel.BindableAttribute有些东西不需要数据绑定。同样,减少了UI开发人员需要做的工作。

我也喜欢DefaultValue劳伦斯·约翰斯顿(Lawrence Johnston)提到的内容。

System.ComponentModel.BrowsableAttribute并且Flags经常使用。

System.STAThreadAttribute System.ThreadStaticAttribute 在需要时使用。

顺便说说。对于所有.Net框架开发人员来说,这些都是一样有价值的。


8

[EditorBrowsable(EditorBrowsableState.Never)]如果项目不在您的解决方案中,则允许您从IntelliSense隐藏属性和方法。对于为流利的接口隐藏无效流非常有用。您想多久获取一次GetHashCode()或Equals()?

对于MVC,[ActionName("Name")]允许您具有具有相同方法签名的Get操作和Post操作,或在操作名称中使用破折号,否则,如果不为其创建路由,则将无法实现。


8

我认为在此提及以下属性也很重要:

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

STAThread是否用于防止您的应用程序在启动时意外剥离其自身的另一个实例?
发光

7

在我脑海中,这是我在大型项目中实际使用的预定义属性的快速列表(大致按使用频率排序)(约50万个LoC):

标志,可序列化,WebMethod,COMVisible,TypeConverter,条件,ThreadStatic,已过时,InternalsVisibleTo,DebuggerStepThrough。


2
+1为ThreadStatic感到惊讶,到目前为止,还没有人提及它,也为统计方法感到惊讶
staafl 2013年

6

我通过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;
    }
}
}


5

[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() { }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.