您的位置:首页 > 编程语言 > C#

C# 特性

2016-06-07 17:54 423 查看
1.特性功能:

用以将元数据或声明信息与代码(程序集、类型、方法、属性等)相关联。特性与程序实体相关联后,即可在运行时用反射技术查询特性。

2.使用特性:

特性可以放置在几乎所有的声明中(但特定的特性可能限制在其上有效的声明类型)。

2.1.普通特性:

[System.Serializable]
public class SampleClass
{
// Objects of this type can be serialized.
}
2.2.具有
DllImportAttribute 特性的方法的声明如下:

using System.Runtime.InteropServices;
[DllImport("user32.dll")]
extern static void SampleMethod();
2.3.一个声明上可放置多个特性:

using System.Runtime.InteropServices;


static void MethodA([In][Out] ref double x)
{

}
static void MethodB([Out][In] double x)
{

}
static void MethodC([Out, In]double x)
{

}


2.4.某些特性对于给定实体可以指定多次,如, ConditionalAttribute就是一个可以多次使用的特性:

[Conditional("DEBUG"), Conditional("TEST1")]
void TraceMethod()
{
// ...
}


3.特性参数:

定位参数(特性类的构造函数的参数)、属性参数(特性类中的属性),也叫命名参数

定位参数是必填的且必须按顺序指定, 属性参数是可选的且可以按任意顺序指定。定位参数必须在前。

[DllImport("user32.dll")]
[DllImport("user32.dll", SetLastError=false, ExactSpelling=false)]
[DllImport("user32.dll", ExactSpelling=false, SetLastError=false)]
第一个参数(DLL 名称)是定位参数并且总是第一个出现,其他参数为命名参数。在这种情况下,两个命名参数均默认为 false,因此可将其省略。有关默认参数值的信息,请参考各个特性的文档。

4.特性目标:

特性的目标是应用该特性的实体,特性可以应用于类、特定方法或整个程序集。默认情况下,特性应用于它后面的元素。但是,您也可以显式标识要将特性应用于类,方法还是它的参数或返回值。

若要显式标识特性目标,请使用下面的语法来应用特性到目标上:

[target : attribute-list]


特性的目标列表:

C#

Visual Basic
适用对象
assembly
Assembly
整个程序集
module
Module
当前程序集模块(不同于 Visual Basic 模块)
field
不支持
在类或结构中的字段
event
不支持
event
method
不支持
方法或 getset 属性访问器
param
不支持
方法参数或 set 属性访问器参数
property
不支持
属性
return
不支持
方法、属性索引器或 get 属性访问器的返回值
type
不支持
结构、类、接口、枚举或委托
举例:
将特性应用于程序集和模块:

[assembly:AssemblyTitle("Production assembly4")]


[module:CLSCompliant(true)]
将特性应用于方法、方法参数和方法返回值:

[method:MyAttr]
static int Method()
{
return 1;
}
或
    [MyAttr]
        static int Method()
        {
            return 1;
        }
// applies to return value
[return: SomeAttr]
int Method3() { return 0; }
[property:SomeAttr]
public int Age{get;set;};
或
[SomeAttr]
      public int Age{get;set;};
无论规定 SomeAttr 应用于什么目标,都必须指定 return 目标,即使 SomeAttr 被定义为仅应用于返回值也是如此。换言之,编译器将不使用 AttributeUsage 信息解析不明确的特性目标。

5.特性的用途:

5.1.在Web服务中, 使用WebMethod特性来标记方法, 以指示该方法可以通过SOAP协议进行调用,

5.2.描述当与本机代码进行交互操作时如何封送方法参数(MarshalAsAttribute)

5.3.描述类、方法和接口的 COM 属性。

5.4.使用 DllImportAttribute 类调用非托管代码。

5.5.在标题、版本、说明或商标方面描述您的程序集。

5.6.描述要持久性序列化类的哪些成员。

5.7.描述如何映射类成员和 XML 节点以便进行 XML 序列化。

5.8.描述方法的安全要求。

5.9.指定用于强制安全性的特性。

5.11.由实时 (JIT) 编译器控制优化,以便易于调试代码。

5.12.获取有关调用方的信息的方法。

6.C#常用特性:

6.1.全局特性:

用于整个程序集或模块:如:AssemblyVersionAttribute用于向程序集中嵌入版本信息:

[assembly: AssemblyVersion("1.0.0.0")]


6.2.过时特性:

Obsolete 属性指示某个程序实体标记为建议不再使用的一个。 每次使用Obsolete标记过的实体会出现警告或错误提示。

[System.Obsolete("use NewMethod", true)]
public void OldMethod() { }


6.3.条件特性:Conditional

利用 Conditional 属性,程序员可以定义条件方法。Conditional 属性通过测试条件编译符号来确定适用的条件。当运行到一个条件方法调用时,是否执行该调用,要根据出现该调用时是否已定义了此符号来确定。如果定义了此符号,则执行该调用;否则省略该调用(包括对调用的参数的计算):

<strong>#define TRACE_ON</strong>
using System;
using System.Diagnostics;

public class Trace
{
[Conditional("TRACE_ON")]
public static void Msg(string msg)
{
Console.WriteLine(msg);
}
}

public class ProgramClass
{
static void Main()
{
Trace.Msg("Now in Main...");
Console.WriteLine("Done.");
}<pre name="code" class="csharp">#if DEBUG
void ConditionalMethod()
{
}
#endif


}


如果没#define TRANCE_ON这一指令,则在main函数中不执行Msg方法,直接输出Done.Conditional 一般用于在程序Debug版本中使用DEBUG标识符来启用跟踪并记录功能:

[Conditional("DEBUG")]//DEBUG指令是系统指令,不用再用#define DEBUG定义
static void DebugMethod()
{
}
此时,在Debug版本中会调用DebugMethod,在Release版本中会跳过对他的调用。效果和#if DEBUG...#endif一样

如果一个方法有多个Condigional特性,则只要有一个条件符号被定义了,则该方法就会被调用。(相当于用or连接多个特性)

[Conditional("A"), Conditional("B")]
static void DoIfAorB()
{
// ...
}//A,B中只要有一个被定义了, 就会调用。
Condigional也可用于特性本身:

[Conditional("DEBUG")]
public class DocumentationAttribute : System.Attribute
{
string text;

public DocumentationAttribute(string text)
{
this.text = text;
}
}

class SampleClass
{
// This attribute will only be included if DEBUG is defined.
[Documentation("This method displays an integer.")]//只有定义了DEBUG命令时,Dowork才能应用Documentation特性。
static void DoWork(int i)
{
System.Console.WriteLine(i.ToString());
}
}


6.4.调用方信息特性:

使用调用方信息特性, 可以获取调用方的信息, 并将它传递给方法。可以获取源代码文件路径,行号和调用方的成员名称:

CallerFilePathAttribute:包含调用方源文件在编译时的完整路径。

CallerLineNumberAttribute:在调用方法的源文件中的行号。

CallerMemberNameAttribute:方法名称或调用方的属性名称。

static void Main(string[] args)
{
TraceMessage("Something happened.");
Console.ReadKey();
}
public static void TraceMessage(string message,
[System.Runtime.CompilerServices.CallerMemberName] string memberName = "",
[System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "",
[System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0)
{
System.Diagnostics.Trace.WriteLine("message: " + message);
System.Diagnostics.Trace.WriteLine("member name: " + memberName);
System.Diagnostics.Trace.WriteLine("source file path: " + sourceFilePath);
System.Diagnostics.Trace.WriteLine("source line number: " + sourceLineNumber);
}
输出:
message: Something happened.
member name: Main
source file path: d:\Myprojects\MyTestProjects\AttributeTest\Program.cs
source line number: 17


6.5.DllImportAttribute特性:using System.Runtime.InteropServices
http://blog.csdn.net/hbqhdlc/article/details/6843650
6.5.1.使用DllImport特性可以直接调用一些已经存在的功能(如windows中的一些功能, C++中已经编写好的一些方法),它的功能是提供从非托管DLL导出的函数进行调用所必须的信息。该特性只能应用于方法, 要求

最少要提供包含入口点的dll的名称。

(托管DLL:指完全由.NET 托管代码实现的DLL,完全依赖于.NET平台的CLR运行, 受.NET CLR管控, 支持内存自动回收,对.NET平台是安全的DLL,非托管DLL:指完全或部分不是用.NET代码实现,

不依赖于.NET平台即可运行, 如COM方式的DLL,不支持内存自动回收, 对.NET平台而言,也是非安全的。)

6.5.2.说明:

6.5.2.1.DllImport只能放置在方法声明上。

6.5.2.2.DllImport具有单个定位参数:指定包含被导入方法的dll名称的dllName参数。

6.5.2.3.DllImport具有五个命名参数:

a.CallingConvention参数指示入口点的调用约定,如果未指定CallingConvention,则使用默认值CallingConvention.Winapi.

b.CharSet参数指定用再入口点的字符集, 如果未指定, 则默认CharSet.Auto.

c.EntryPoint参数给出dll中入口点的名称, 如果未指定, 则默认使用方法本身的名称。

d.ExactSpelling参数指示EntryPoint是否必须与指示的入口点的拼写完全匹配,如果未指定, 则默认false.

e.PreserveSig参数指示方法的签名被保留还是被转换,当签名被转换时, 它被转换为一个具有HRESULT返回值和该返回值的一个名为retval的附加输出参数的签名,如果未指定,则true.

f.SetLastError参数指示方法是否保留Win32"上一错误",默认false.

6.5.2.4.DllImport修饰的方法必须具有extern修饰符。

6.5.3.举例:

使用DllImport特性导入Win32的MessageBox函数:

[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern int MessageBox(IntPtr hWnd, String text, String caption, uint type);

MessageBox(<span style="color:Blue;">new</span> IntPtr(0), <span style="color:#A31515;">"Hello World!"</span>, <span style="color:#A31515;">"Hello Dialog"</span>, 0);
在调用MessageBox时就会弹出提示框。

[DllImport("kernel32.dll")]
public static extern bool Beep(int frequency, int duration);//调用Beep()API来发出声音


6.5.4.DllImport路径问题:

会按照顺序自动去寻找dll:exe所在目录->System32所在目录->环境变量目录。

所以只需要你把引用的DLL 拷贝到这三个目录下 就可以不用写路径了。

7.自定义特性:

通过定义一个特性类,可以创建您自己的自定义特性。该特性类直接或间接地从 Attribute 派生,有助于方便快捷地在元数据中标识特性定义。

[System.AttributeUsage(System.AttributeTargets.Class |
System.AttributeTargets.Struct,
AllowMultiple = true)  // multiuse attribute
]
public class Author : System.Attribute
{
<span style="color:Blue;">private</span> <span style="color:Blue;">string</span> name;
<span style="color:Blue;">public</span> <span style="color:Blue;">double</span> version;
 <span style="color:Blue;">public</span> Author(<span style="color:Blue;">string</span> name)
{
<span style="color:Blue;">this</span>.name = name;
version = 1.0;
}
}


如果特性类包含一个属性,则该属性必须为读写属性。

8.使用反射访问(检索)自定义特性:
如果没有检索自定义特性的信息和对其进行操作的方法,则定义自定义特性并将其放置在源代码中就没有意义。使用反射,可检索用自定义特性定义的信息。主要方法是
GetCustomAttributes,它返回对象数组,这些对象在运行时等效于源代码特性。

private static void PrintAuthorInfo(Type t)
{
Console.WriteLine("Author information for {0}",t);
Attribute[] attr = Attribute.GetCustomAttributes(t);
foreach (Attribute item in attr)
{
if (item is Author)
{
Author a = (Author)item;
Console.WriteLine( "{0},Version{1:f}",a.GetName(),a.version);
}
}
}


[System.AttributeUsage(System.AttributeTargets.Class |
System.AttributeTargets.Struct,
AllowMultiple = true)  // Multiuse attribute.
]
public class Author : System.Attribute
{
string name;
public double version;

public Author(string name)
{
this.name = name;

// Default value.
version = 1.0;
}

public string GetName()
{
return name;
}
}
// Class with the Author attribute.
[Author("P. Ackerman")]
public class FirstClass
{
// ...
}
PrintAuthorInfo(typeof(FirstClass));
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: