.NET 中的属性是什么?
-
09-06-2019 - |
题
.NET 中的属性是什么,它们有什么用处,以及如何创建自己的属性?
解决方案
元数据。有关您的对象/方法/属性的数据。
例如,我可能声明一个名为: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; }
}
}
请记住,当您使用属性时,您可以省略后缀“attribute”,编译器将为您添加该后缀。
笔记: 属性本身不执行任何操作 - 需要有一些其他代码来使用它们。有时该代码是为您编写的,但有时您必须自己编写。例如,C# 编译器关心某些框架,并且某些框架使用某些框架(例如当加载程序集时,NUnit 在类上查找 [TestFixture],在测试方法上查找 [Test]。
因此,在创建您自己的自定义属性时,请注意它根本不会影响代码的行为。您需要编写检查属性(通过反射)并对其进行操作的其他部分。
其他提示
很多人都回答过,但到目前为止还没有人提到这一点......
属性大量使用反射。反射已经相当慢了。
这是 非常值得 将您的自定义属性标记为 sealed
类来提高其运行时性能。
考虑在哪里适合使用这样的属性也是一个好主意,并通过属性(!)来表明这一点 AttributeUsage
. 。可用属性用法列表可能会让您感到惊讶:
- 集会
- 模块
- 班级
- 结构体
- 枚举
- 构造函数
- 方法
- 财产
- 场地
- 事件
- 界面
- 范围
- 代表
- 返回值
- 通用参数
- 全部
AttributeUsage 属性是 AttributeUsage 属性签名的一部分,这一点也很酷。哇哦,循环依赖!
[AttributeUsageAttribute(AttributeTargets.Class, Inherited = true)]
public sealed class AttributeUsageAttribute : Attribute
属性是一种用于标记类的元数据。例如,这通常在 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;
}
}
}
如果您想了解更多相关信息,您可以随时查看 微软软件定义网络 其中有一个很好的描述。
我希望这对您有所帮助!
属性是一个类,其中包含一些可应用于代码中的对象的功能。要创建一个,请创建一个继承自 System.Attribute 的类。
至于他们有什么好处……它们的用途几乎是无限的。
属性就像应用于类、方法或程序集的元数据。
它们适用于许多事情(调试器可视化、将事物标记为过时、将事物标记为可序列化,列表是无穷无尽的)。
创建您自己的定制产品非常简单。从这里开始:
http://msdn.microsoft.com/en-us/library/sw480ze8(VS.71).aspx
在我目前正在进行的项目中,有一组各种风格的 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是可憎的,但这是我必须使用的:-()
您可以为大多数事物添加属性,并且有一系列预定义的属性。上面提到的编辑器还会查找描述该属性以及如何编辑该属性的属性的自定义属性。
一旦你明白了整个想法,你就会想知道如果没有它们你是如何生活的。
如前所述,属性相对容易创建。工作的另一部分是创建使用它的代码。在大多数情况下,您将在运行时使用反射来根据属性或其特性的存在来改变行为。在某些情况下,您将检查已编译代码的属性以进行某种静态分析。例如,参数可能被标记为非空,分析工具可以使用它作为提示。
使用属性并了解其使用的适当场景是大部分工作。
本质上,属性是您想要附加到您的 类型 (类、方法、事件、枚举等)
这个想法是在运行时一些其他类型/框架/工具将查询 你的 在属性中键入信息并对其进行操作。
因此,例如,Visual Studio 可以查询第 3 方控件上的属性,以确定该控件的哪些属性应在设计时出现在“属性”窗格中。
属性还可以在面向方面的编程中使用,根据装饰对象的属性并添加验证、日志记录等,在运行时注入/操作对象。不影响对象的业务逻辑。
您可以使用自定义属性作为在子类中定义标记值的简单方法,而无需为每个子类一遍又一遍地编写相同的代码。我遇到了一个不错的 约翰·沃特斯 (John Waters) 的简洁示例 如何在您自己的代码中定义和使用自定义属性。
有一个教程位于 http://msdn.microsoft.com/en-us/library/aa288454(VS.71).aspx
要开始创建属性,请打开 C# 源文件,输入 attribute
并点击 [TAB]。它将扩展为新属性的模板。
属性也常用于面向方面的编程。有关此示例,请查看 后锐利 项目。