C#-特性(Attribute)
<h2><span style="font-size: 15px">概念</span></h2><p><span style="font-size: 15px">特性是一种允许我们向程序的程序集添加元数据的语言结构,它是用于保存程序结构信息的某种特殊类型的类。</span><br><span style="font-size: 15px">可以通过使用特性向程序添加声明性信息。一个声明性标签是通过放置在它所应用的元素前面的方括号([ ])来描述的。</span><br><span style="font-size: 15px">MSDN解释为:特性提供功能强大的方法,用以将元数据或声明信息与代码(程序集、类型、方法、属性等)相关联。特性与程序实体关联后,即可在运行时使用名为“反射”的技术查询特性。</span><br><span style="font-size: 15px">特性(Attribute)用于添加元数据,如编译器指令和注释、描述、方法、类等其他信息。.Net 框架提供了两种类型的特性:预定义特性和自定义特性。</span><br><strong><span style="font-size: 15px">特性具有以下属性:</span></strong></p>
<ul>
<li><span style="font-size: 15px">特性可向程序中添加元数据。元数据是有关在程序中定义的类型的信息。所有的 .NET 程序集都包含指定的一组元数据,这些元数据描述在程序集中定义的类型和类型成员。可以添加自定义特性,以指定所需的任何附加信息。</span></li>
<li><span style="font-size: 15px">可以将一个或多个特性应用到整个程序集、模块或较小的程序元素(如类和属性)。</span></li>
<li><span style="font-size: 15px">特性可以与方法和属性相同的方式接受参数。</span></li>
<li><span style="font-size: 15px">程序可以使用反射检查自己的元数据或其他程序内的元数据。</span></li>
</ul>
<h2><span style="font-size: 15px">使用特性</span></h2>
<p><span style="font-size: 15px">特性的目的是告诉编译器把程序结构的某组元数据嵌入程序集,它可以放置在几乎所有的声明中(但特定的属性可能限制在其上有效的声明类型)。</span><br><span style="font-size: 15px">在 C# 中,特性的指定方法为:将括在方括号中的特性名置于其应用到的实体的声明上方。</span><br><span style="font-size: 15px">例如:</span></p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:false;">
public class SampleClass
{
// 运行语句
}</pre>
</div>
<p><span style="font-size: 15px">一个声明中可以放置多个特性,有两种写法。第一种是将独立的特性片段互相叠在一起,第二种是使用一个特性片段,特性之间使用逗号分割。</span></p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:false;">
// 独立的特性片段
public class SampleClass
{
// 运行语句
}
// 逗号分割使用
public class SampleClass
{
// 运行语句
}</pre>
</div>
<p><span style="font-size: 15px">对于某些特性可以对给定实体进行指定多次。例如 ConditionalAttribute :</span></p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:false;">
void TraceMethod()
{
// 运行语句
}
</pre>
</div>
<p> </p>
<h2><span style="font-size: 15px">特性目标</span></h2>
<p><span style="font-size: 15px">特性的目标是应用该特性的实体。例如,特性可以应用于类、特定方法或整个程序集。默认情况下,特性应用于它后面的元素。但是,您也可以显式标识要将特性应用于方法还是它的参数或返回值。</span><br><span style="font-size: 15px">语法:</span></p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:false;"></pre>
</div>
<p><span style="font-size: 15px"><img src="https://img2020.cnblogs.com/blog/1359074/202009/1359074-20200907175845953-852823704.png" alt="" loading="lazy"></span></p>
<h2><span style="font-size: 15px">预定义特性</span></h2>
<p><span style="font-size: 15px">.Net 框架提供了三种预定义特性:AttributeUsage、Conditional、Obsolete。</span></p>
<h3><span style="font-size: 15px">AttributeUsage</span></h3>
<p><span style="font-size: 15px">AttributeUsage 描述了如何使用一个自定义特性类。它规定了特性可应用到的项目的类型。</span><br><span style="font-size: 15px">语法:</span></p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:false;">[AttributeUsage(
validon,
AllowMultiple=allowmultiple,
Inherited=inherited
)]
</pre>
</div>
<p> </p>
<p><span style="font-size: 15px">参数说明:</span></p>
<ul>
<li><span style="font-size: 15px">validon: 规定特性可被放置的语言元素。它是枚举器 AttributeTargets 的值的组合。默认值是 AttributeTargets.All。</span></li>
<li><span style="font-size: 15px">allowmultiple:可选的参数,为该特性的 AllowMultiple 属性(property)提供一个布尔值。如果为 true,则该特性是多用的。默认值是 false(单用的)。</span></li>
<li><span style="font-size: 15px"> inherited:可选的参数,为该特性的 Inherited 属性(property)提供一个布尔值。如果为 true,则该特性可被派生类继承。默认值是 false(不被继承)。</span></li>
</ul>
<p><span style="font-size: 15px">示例:</span></p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:false;">[AttributeUsage(AttributeTargets.Class |
AttributeTargets.Constructor |
AttributeTargets.Field |
AttributeTargets.Method |
AttributeTargets.Property,
AllowMultiple = true)]</pre>
</div>
<p><span style="font-size: 15px">这个预定义特性标记了一个条件方法,其执行依赖于它顶的预处理标识符。</span><br><span style="font-size: 15px">它会引起方法调用的条件编译,取决于指定的值,比如 Debug 或 Trace。例如,当调试代码时显示变量的值。</span><br><span style="font-size: 15px">语法:</span></p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:false;">[Conditional(
conditionalSymbol
)]
</pre>
</div>
<p> </p>
<p><span style="font-size: 15px">示例:</span></p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:false;">using System;
using System.Diagnostics;
namespace C_Pro
{
public class Myclass
{
public static void Msg(string msg)
{
Console.WriteLine(msg);
}
}
public class Test
{
static void Main()
{
Myclass.Msg("debug in Main.");
Console.WriteLine("Done.");
Console.ReadKey();
}
}
}</pre>
</div>
<p><span style="font-size: 15px">以debug模式进行运行:</span></p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:false;">debug in Main.
Done.</pre>
</div>
<h3><span style="font-size: 15px">Obsolete</span></h3>
<p><span style="font-size: 15px">这个预定义特性标记了不应被使用的程序实体。它可以让您通知编译器丢弃某个特定的目标元素。</span><br><span style="font-size: 15px">语法:</span></p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:false;">[Obsolete(
message,
iserror
)] </pre>
</div>
<p><span style="font-size: 15px">参数说明:</span></p>
<ul>
<li><span style="font-size: 15px">message:是一个字符串,描述项目为什么过时的原因以及该替代使用什么。</span></li>
<li><span style="font-size: 15px">iserror:是一个布尔值。如果该值为 true,编译器应把该项目的使用当作一个错误。默认值是 false(编译器生成一个警告)。</span></li>
</ul>
<p><span style="font-size: 15px">示例:</span></p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:false;">using System;
namespace C_Pro
{
public class MyClass
{
static void OldMethod()
{
Console.WriteLine("It is the old method");
}
static void NewMethod()
{
Console.WriteLine("It is the new method");
}
public static void Main()
{
OldMethod();
NewMethod();
Console.ReadKey();
}
}
}</pre>
</div>
<p><span style="font-size: 15px">运行后结果:</span></p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:false;">Main.cs(20,4): error CS0619: `C_Pro.MyClass.OldMethod()' is obsolete: `Don't use OldMethod, use NewMethod instead'
Main.cs(21,4): warning CS0618: `C_Pro.MyClass.NewMethod()' is obsolete: `Don't use OldMethod, use NewMethod instead'
Compilation failed: 1 error(s), 1 warnings</pre>
</div>
<p><span style="font-size: 15px">如果在 VS 中可以直接看到 OldMethod() 会报错提示:</span></p>
<p><span style="font-size: 15px"><img src="https://img2020.cnblogs.com/blog/1359074/202009/1359074-20200907180638718-1694966242.png" alt="" loading="lazy"></span></p>
<h2><span style="font-size: 15px">自定义特性</span></h2>
<p><span style="font-size: 15px">声明特性和声明其他类是一样的,只是所有的特性都派生自System.Attribute。</span><br><span style="font-size: 15px">根据约定,所有特性名称都以单词“Attribute”结束,以便将它们与“.NET Framework”中的其他项区分。但是,在代码中使用特性时,不需要指定 attribute 后缀。</span><br><span style="font-size: 15px">例如定义一个MyAttributeAttribute,由 System.Attribute 派生而来,因此是自定义特性类。</span></p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:false;">public class MyAttributeAttribute : System.Attribute
{
public string product;
public string Description;
public MyAttributeAttribute(string product)
{
this.product = product;
Description = "";
}
}</pre>
</div>
<p><span style="font-size: 15px">特性也有构造函数。和其他类一样,每个特性至少有一个公共构造函数,如果没有声明构造函数,编译器则会产生一个隐式、公共且无参的构造函数。</span><br><span style="font-size: 15px">构造函数的参数是自定义特性的定位参数。例如上面的示例中 product 是定位参数,Description 是命名参数。任何公共的读写字段或属性都是命名参数。</span><br><span style="font-size: 15px">定义完成后使用特性:</span></p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:false;">
class SampleClass
{
// 执行语句
}</pre>
</div>
<h2><span style="font-size: 15px">特性与注释的区别</span></h2>
<p><span style="font-size: 15px">注释是对程序源代码的一种说明,主要目的是给人看的,在程序被编译的时候会被编译器所丢弃,因此,它丝毫不会影响到程序的执行。</span></p>
<p><span style="font-size: 15px">Attribute是程序代码的一部分,它不但不会被编译器丢弃,而且还会被编译器编译进程序集(Assembly)的元数据(Metadata)里。在程序运行的时候,随时可以从元数据(元数据:.NET中元数据是指程序集中的命名空间、类、方法、属性等信息,这些信息是可以通过Reflection读取出来的。)中提取提取出这些附加信息,并以之决策程序的运行。</span></p>
<p><span style="font-size: 15px"> </span></p><br><br>
来源:https://www.cnblogs.com/tynam/p/13628286.html
頁:
[1]