.NET中的属性是什么?


Answers:


146

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

例如,我可以声明一个名为: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组件时,始终在SomeDate之前显示SomeInt。

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

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

例如,告诉设计人员不要在设计时在“属性”窗口的可用属性中列出该属性。

可能还使用它们生成代码,预编译操作(如后夏普)或运行时操作如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; }
    }
}

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

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


32
对于其价值,这是所有(内置).NET属性的列表:msdn.microsoft.com/zh-cn/library/aa311259
VS.71).aspx

1
您将如何使用“ SomeProfilingMethod”作为属性?
RayLoveless '16

@RayLoveless不是属性,SomeProfilingMethod是用于寻找属性的工具代码。具体来说,在示例中,我给出了寻找“选择退出”属性(NoTimingAttribute)而不是“选择加入”属性的方法。想法是,它决定了一切。
Quibblesome

@Quibblesome是否可以添加诸如“属性本身无法执行任何操作-需要使用其他代码(编译器关心夫妇,不同的框架使用某些属性)。”仅创建属性不会影响代码的行为-您需要编写检查属性(通过反射)并对其执行操作的另一部分”。(或者,如果您还可以,我可以这样做)。许多人期望属性神奇地起作用,这里没有答案可以澄清这一点。(或只是链接到stackoverflow.com/questions/4879521/…进行了介绍)
Alexei Levenkov,

仅当您停止使用Bing时。没事 j / k我使用DuckDuckGo作为主要对象,主要使用Bing iirc。:)
Quibblesome

36

到目前为止,很多人都回答了,但没有人提及。

属性与反射一起大量使用。反思已经相当缓慢。

这是非常值得的标记您的自定义属性为sealed班提高自己的运行时性能。

考虑在何处使用这样的属性,并为您的属性(!)指明属性,也是一个好主意AttributeUsage。可用属性用法列表可能会让您感到惊讶:

  • 部件
  • 模组
  • 结构
  • 枚举
  • 建设者
  • 方法
  • 属性
  • 领域
  • 事件
  • 接口
  • 参数
  • 代表
  • 返回值
  • 通用参数
  • 所有

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

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

13

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

首先创建一个属性:

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

    public SortOrderAttribute(int sortOrder)
    {
        this.SortOrder = sortOrder;
    }
}

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

[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,它具有很好的描述。
希望这对您有所帮助!




5

在我目前正在从事的项目中,有一组各种口味的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是可憎的,但这是我必须使用的:-()

您可以将属性放在大多数事物上,并且有很多预定义的属性。上面提到的编辑器还在属性上寻找自定义属性,这些属性描述了属性以及如何对其进行编辑。

一旦有了完整的想法,您会想知道没有它们的生活。


4

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

使用属性并了解使用它们的适当方案是大部分工作。


3

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

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

因此,例如,Visual Studio可以查询第三方控件上的属性,以弄清楚该控件的哪些属性应在设计时显示在“属性”窗格中。

属性也可以在面向方面的编程中使用,以便在运行时基于装饰对象的属性并在不影响对象业务逻辑的情况下向对象添加验证,日志记录等属性。




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.