【问题标题】:What are attributes in .NET?.NET 中的属性是什么?
【发布时间】:2010-09-06 10:16:12
【问题描述】:

.NET 中的属性是什么,它们有什么用处,以及如何创建自己的属性?

【问题讨论】:

    标签: c# .net glossary .net-attributes


    【解决方案1】:

    元数据。有关您的对象/方法/属性的数据。

    例如,我可能会声明一个名为:DisplayOrder 的属性,这样我就可以轻松地控制属性在 UI 中的显示顺序。然后我可以将它附加到一个类并编写一些 GUI 组件来提取属性并对 UI 元素进行适当的排序。

    public class DisplayWrapper
    {
        private UnderlyingClass underlyingObject;
    
        public DisplayWrapper(UnderlyingClass u)
        {
            underlyingObject = u;
        }
    
        [DisplayOrder(1)]
        public int SomeInt
        {
            get
            {
                return underlyingObject .SomeInt;
            }
        }
    
        [DisplayOrder(2)]
        public DateTime SomeDate
        {
            get
            {
                return underlyingObject .SomeDate;
            }
        }
    }
    

    从而确保在使用我的自定义 GUI 组件时 SomeInt 始终显示在 SomeDate 之前。

    但是,您会看到它们最常用于直接编码环境之外。例如,Windows 设计器广泛使用它们,因此它知道如何处理自定义对象。像这样使用 BrowsableAttribute:

    [Browsable(false)]
    public SomeCustomType DontShowThisInTheDesigner
    {
        get{/*do something*/}
    }
    

    例如,告诉设计者不要在设计时将其列在“属性”窗口的可用属性中。

    可以也将它们用于代码生成、预编译操作(例如 Post-Sharp)或运行时操作(例如 Reflection.Emit)。 例如,您可以编写一些代码来进行分析,透明地包装您的代码进行的每个调用并对其计时。您可以通过放置在特定方法上的属性“选择退出”时间。

    public void SomeProfilingMethod(MethodInfo targetMethod, object target, params object[] args)
    {
        bool time = true;
        foreach (Attribute a in target.GetCustomAttributes())
        {
            if (a.GetType() is NoTimingAttribute)
            {
                time = false;
                break;
            }
        }
        if (time)
        {
            StopWatch stopWatch = new StopWatch();
            stopWatch.Start();
            targetMethod.Invoke(target, args);
            stopWatch.Stop();
            HandleTimingOutput(targetMethod, stopWatch.Duration);
        }
        else
        {
            targetMethod.Invoke(target, args);
        }
    }
    

    声明它们很容易,只需创建一个继承自 Attribute 的类。

    public class DisplayOrderAttribute : Attribute
    {
        private int order;
    
        public DisplayOrderAttribute(int order)
        {
            this.order = order;
        }
    
        public int Order
        {
            get { return order; }
        }
    }
    

    请记住,当您使用属性时,您可以省略后缀“属性”,编译器会为您添加。

    注意:属性本身不会做任何事情 - 需要一些其他代码使用它们。有时该代码是为您编写的,但有时您必须自己编写。例如,C# 编译器关心某些框架和框架使用的某些框架(例如,NUnit 在加载程序集时在类上查找 [TestFixture] 并在测试方法上查找 [Test])。
    因此,在创建自己的自定义属性时,请注意它根本不会影响代码的行为。您需要编写检查属性(通过反射)并对其采取行动的另一部分。

    【讨论】:

    • 不管怎样,这是所有(内置).NET 属性的列表:msdn.microsoft.com/en-us/library/aa311259(VS.71).aspx
    • 如何使用“SomeProfilingMethod”作为属性?
    • @RayLoveless 它不是一个属性, SomeProfilingMethod 是正在寻找分析属性的检测代码。特别是在示例中,我给出了它寻找“选择退出”属性(NoTimingAttribute)而不是“选择加入”属性的方法。这个想法是它对一切都进行计时。
    • @Quibblesome 你可以添加类似“属性不会自己做任何事情 - 需要一些 other 代码来使用它们(编译器关心几个不同的框架使用一些)。仅创建属性不会影响代码的行为 - 您需要编写检查属性(通过反射)并对其采取行动的另一部分“。 (或者如果你没问题,我可以这样做)。许多人期望属性能神奇地起作用,但这里的答案都没有说明这一点。 (或者只是链接到覆盖它的stackoverflow.com/questions/4879521/…
    • 仅当您停止使用必应时。不。 j/k 我使用 DuckDuckGo 作为主要使用 Bing iirc 的主要工具。 :)
    【解决方案2】:

    很多人都回答了,但到目前为止还没有人提到这个......

    属性在反射中被大量使用。反射已经很慢了。

    非常值得将您的自定义属性标记为 sealed 类以提高它们的运行时性能。

    考虑在什么地方适合使用此类属性也是一个好主意,并通过AttributeUsage 将您的属性 (!) 归因于表明这一点。可用属性用法列表可能会让您感到惊讶:

    • 组装
    • 模块
    • 结构
    • 枚举
    • 构造函数
    • 方法
    • 财产
    • 字段
    • 事件
    • 接口
    • 参数
    • 委托
    • 返回值
    • 通用参数
    • 全部

    AttributeUsage 属性是 AttributeUsage 属性签名的一部分也很酷。哇哦循环依赖!

    [AttributeUsageAttribute(AttributeTargets.Class, Inherited = true)]
    public sealed class AttributeUsageAttribute : Attribute
    

    【讨论】:

      【解决方案3】:

      属性是一种用于标记类的元数据。这通常在 WinForms 中使用,例如从工具栏中隐藏控件,但可以在您自己的应用程序中实现,以使不同类的实例以特定方式运行。

      首先创建一个属性:

      [AttributeUsage(AttributeTargets.Class, AllowMultiple=false, Inherited=true)]
      public class SortOrderAttribute : Attribute
      {
          public int SortOrder { get; set; }
      
          public SortOrderAttribute(int sortOrder)
          {
              this.SortOrder = sortOrder;
          }
      }
      

      所有属性类必须有后缀“属性”才有效。
      完成后,创建一个使用该属性的类。

      [SortOrder(23)]
      public class MyClass
      {
          public MyClass()
          {
          }
      }
      

      现在您可以通过执行以下操作来检查特定类的SortOrderAttribute(如果有的话):

      public class MyInvestigatorClass
      {
          public void InvestigateTheAttribute()
          {
              // Get the type object for the class that is using
              // the attribute.
              Type type = typeof(MyClass);
      
              // Get all custom attributes for the type.
              object[] attributes = type.GetCustomAttributes(
                  typeof(SortOrderAttribute), true);
      
              // Now let's make sure that we got at least one attribute.
              if (attributes != null && attributes.Length > 0)
              {
                  // Get the first attribute in the list of custom attributes
                  // that is of the type "SortOrderAttribute". This should only
                  // be one since we said "AllowMultiple=false".
                  SortOrderAttribute attribute = 
                      attributes[0] as SortOrderAttribute;
      
                  // Now we can get the sort order for the class "MyClass".
                  int sortOrder = attribute.SortOrder;
              }
          }
      }
      

      如果您想了解更多有关此内容的信息,您可以随时查看MSDN,它的描述非常好。
      希望对您有所帮助!

      【讨论】:

        【解决方案4】:

        属性是一个包含一些功能的类,您可以将这些功能应用于代码中的对象。要创建一个,请创建一个继承自 System.Attribute 的类。

        至于它们有什么用处……它们的用途几乎是无限的。

        http://www.codeproject.com/KB/cs/dotnetattributes.aspx

        【讨论】:

        • “功能”在这里是错误的词;它们是元数据,而不是功能
        【解决方案5】:

        属性就像应用于类、方法或程序集的元数据。

        它们适用于任何数量的事物(调试器可视化、将事物标记为过时、将事物标记为可序列化、列表无穷无尽)。

        创建自己的自定义项非常容易。从这里开始:

        http://msdn.microsoft.com/en-us/library/sw480ze8(VS.71).aspx

        【讨论】:

          【解决方案6】:

          在我目前正在进行的项目中,有一组不同风格的 UI 对象和一个编辑器,用于组装这些对象以创建用于主应用程序的页面,有点像 DevStudio 中的表单设计器。这些对象存在于它们自己的程序集中,每个对象都是从UserControl 派生的类并具有自定义属性。这个属性是这样定义的:

          [AttributeUsage (AttributeTargets::Class)]
          public ref class ControlDescriptionAttribute : Attribute
          {
          public:
            ControlDescriptionAttribute (String ^name, String ^description) :
              _name (name),
              _description (description)
            {
            }
          
            property String ^Name
            {
              String ^get () { return _name; }
            }
          
            property String ^Description
            {
              String ^get () { return _description; }
            }
          
          private:
            String
              ^ _name,
              ^ _description;
          };
          

          我将它应用到这样的类中:

          [ControlDescription ("Pie Chart", "Displays a pie chart")]
          public ref class PieControl sealed : UserControl
          {
            // stuff
          };
          

          这是之前的海报所说的。

          要使用该属性,编辑器有一个包含控件类型的Generic::List <Type>。有一个列表框,用户可以从该列表框拖放到页面上以创建控件的实例。为了填充列表框,我得到了控件的ControlDescriptionAttribute 并在列表中填写了一个条目:

          // done for each control type
          array <Object ^>
            // get all the custom attributes
            ^attributes = controltype->GetCustomAttributes (true);
          
          Type
            // this is the one we're interested in
            ^attributetype = ECMMainPageDisplay::ControlDescriptionAttribute::typeid;
          
          // iterate over the custom attributes
          for each (Object ^attribute in attributes)
          {
            if (attributetype->IsInstanceOfType (attribute))
            {
              ECMMainPageDisplay::ControlDescriptionAttribute
                ^description = safe_cast <ECMMainPageDisplay::ControlDescriptionAttribute ^> (attribute);
          
              // get the name and description and create an entry in the list
              ListViewItem
                ^item = gcnew ListViewItem (description->Name);
          
              item->Tag = controltype->Name;
              item->SubItems->Add (description->Description);
          
              mcontrols->Items->Add (item);
              break;
            }
          }
          

          注意:以上是 C++/CLI 但转换成 C# 并不难 (是的,我知道,C++/CLI 令人厌恶,但这是我必须使用的 :-()

          您可以将属性放在大多数事物上,并且有一系列预定义的属性。上面提到的编辑器还会在属性上查找描述属性以及如何编辑它的自定义属性。

          一旦你明白了整个想法,你会想知道没有它们你是如何生活的。

          【讨论】:

            【解决方案7】:

            如前所述,属性相对容易创建。工作的另一部分是创建使用它的代码。在大多数情况下,您将在运行时使用反射来根据属性或其属性的存在来改变行为。在某些情况下,您将检查已编译代码的属性以进行某种静态分析。例如,参数可能被标记为非空,分析工具可以将此作为提示。

            使用属性并了解其使用的适当场景是大部分工作。

            【讨论】:

              【解决方案8】:

              属性本质上是您想要附加到您的类型(类、方法、事件、枚举等)的数据位

              这个想法是,在运行时,一些其他类型/框架/工具将查询 您的 类型以获取属性中的信息并对其进行操作。

              因此,例如,Visual Studio 可以查询第 3 方控件的属性,以确定控件的哪些属性应在设计时出现在“属性”窗格中。

              属性还可以在面向切面编程中用于在运行时根据修饰对象的属性注入/操作对象,并向对象添加验证、日志记录等,而不影响对象的业务逻辑。

              【讨论】:

                【解决方案9】:

                您可以使用自定义属性作为在子类中定义标记值的简单方法,而无需为每个子类一遍又一遍地编写相同的代码。我遇到了一个很好的concise example by John Waters,关于如何在您自己的代码中定义和使用自定义属性。

                http://msdn.microsoft.com/en-us/library/aa288454(VS.71).aspx有教程

                【讨论】:

                  【解决方案10】:

                  要开始创建属性,请打开 C# 源文件,键入 attribute 并点击 [TAB]。它将扩展为新属性的模板。

                  【讨论】:

                  • 它是如何回答这个问题的?它应该是评论,而不是答案。
                  【解决方案11】:

                  属性也常用于面向方面的编程。有关此示例,请查看 PostSharp 项目。

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 2012-07-29
                    • 2010-10-31
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2015-07-10
                    相关资源
                    最近更新 更多