clr via c# 定制特性
1,特性的应用范围:特性可应用于程序集,模块,类型,字段,方法,方法参数,方法返回值,属性,参数,泛型参数
2,利用前缀告诉编译器表明意图---下面的倾斜是必须的表明了我们的目标元素:
[assembly: AssemblyTitle("ClrFromCSharp_2_2")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ClrFromCSharp_2_2")]
[assembly: AssemblyCopyright("Copyright © 2020")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")] // 将 ComVisible 设置为 false 会使此程序集中的类型
//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
//请将此类型的 ComVisible 特性设置为 true。
[assembly: ComVisible(true)] // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
[assembly: Guid("8c81c6c1-261e-445a-827d-fabe71033d57")] // 程序集的版本信息由下列四个值组成:
//
// 主版本
// 次版本
// 生成号
// 修订号
//
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
//通过使用 "*",如下所示:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
3,特性的本质是一个类型的实列,并且定制特性类必须从System.Attribute类派生
4,许多类:比如
StructLayoutAttribute
MarshalAsAttribute
DllImportAttribute
InAttribute
OutAttribute
都在命名空间System.Runtime.InteropServices命名空间中.
5,特性对象的构造,应为特性是类的实列,所以其支持类似
[DllImport("avifil32.dll"),CharSet=CharSet.Ansi)]//其中第一个为构造器参数,第二个为公共字段的值
private static extern void AVIFileInit();
6,定制特性的简化写法,
- 两个定制特性可以分开写也可以写一起(使用","分开)
- 定制特性没有先后顺序的区分
- 定制特性如果没有构造器参数,可以省略()
- 定制特性如果后缀是Attribute,可以省略,以下都一样.
[Serializable][Flags]
[Serializable,Flags]
[FlagsAttribute,SerializableAttribute]
[FlagsAttribute(),SerializableAttribute()]
7,定义自己的特性类
假设需要定义类FlagsAttribute
[AttributeUsage(AttributeTargets.Enum,Inherited =false)]
public class FlagsAttribute : Attribute
{
public FlagsAttribute() { }
}
注意上面的AttributeUsage类
- 定制参数指明该定制特性的范围--AttributeTargets--比如Flags只能作用于枚举类
- 指定是否可以将特性用于同一目标 AllowMultiple
- 指定是否将特性应用于派生类和重写的方法:Inherited
- 特性类的实列构造器,字段和属性能用的数据类型并不多,只允许
- Boolean,Char,Byte,SByte,Int16,UInt16,Int32,UInt32,Int64,UInt64,Single,Double,String,Type,Object,Enum.
- 还可以使用上述类型的一维0基数组,但是应尽量避免使用数组.
8,检测定制特性
[AttributeUsage(AttributeTargets.All,Inherited =false)]
public class Flags1Attribute : Attribute
{
public Flags1Attribute() { }
}
// [Flags1]
public class TestAttribute
{
public TestAttribute()
{
if (this.GetType().IsDefined(typeof(Flags1Attribute), false))
Console.WriteLine("the object is Defined the Attribute Flags1");
else
Console.WriteLine("the object is not Defined the Attribute Flags1"); }
public static void Call()
{
TestAttribute a1 = new TestAttribute(); }
}
使用IsDefined函数检测在类的实列中是否使用了特性!注意该方法在MemberInfo类中定义,注意,类Type派生自该类.
- IsDefined()该方法检测是否由指定的Attribute派生类的实列与目标关联
- GetCustomAttribute()---获取特性常用于multiple设为true
public static void Main()
{
try
{
// Get the type of MyClass1.
Type myType = typeof(MyClass1);
// Get the members associated with MyClass1.
MemberInfo[] myMembers = myType.GetMembers(); // Display the attributes for each of the members of MyClass1.
for(int i = 0; i < myMembers.Length; i++)
{
Object[] myAttributes = myMembers[i].GetCustomAttributes(true);
if(myAttributes.Length > 0)
{
Console.WriteLine("\nThe attributes for the member {0} are: \n", myMembers[i]);
for(int j = 0; j < myAttributes.Length; j++)
Console.WriteLine("The type of the attribute is {0}.", myAttributes[j]);
}
}
}
catch(Exception e)
{
Console.WriteLine("An exception occurred: {0}", e.Message);
}
}
当使用GetMembers方法可以获取某个类的所有公开类型,注意,方法,属性,字段,构造器等都是Member之一.
然后利用分别对每一个成员获取其特性属性集合.
9,CustomAttributeExtensions中定义的三个方法
|
说明 |
IsDefined |
public static bool IsDefined (this System.Reflection.MemberInfo element, Type attributeType, bool inherit);//inherit指定是否检查其上级,true则检查,false不检查 |
GetCustomAttributes |
与上述类似,用于获取某个对象(模块,程序集,type,memberinfo,parameterinfo,等)的特性的集合. 返回一个枚举集合. |
GetCustomAttribute |
public static Attribute GetCustomAttribute (this System.Reflection.Assembly element, Type attributeType);//从某个对象里面直接获取这个特性实列. |
10,反射命名空间 System.Reflection 提供了几个类允许检查模块的元数据
- Assembly
- Module
- ParameterInfo
- MemberInfo
- Type
- MethodInfo
- ConstructorInfo
- FieldInfo
- EventInfo
- PropertyInfo
- 及各自的*Builder类
所有类都提供了IsDefined和GetCustomAttributes方法.
11,检测定制特性 注意----MemberInfo--->Type---->TypeInfo.
利用Type
可以获得
- 类的方法
- 类的成员
- 类的字段
- 类的属性
- 类的构造器等
TypeInfo t = typeof(Calendar).GetTypeInfo();
IEnumerable<PropertyInfo> pList = t.DeclaredProperties;
IEnumerable<MethodInfo> mList = t.DeclaredMethods;
查看定制类的方法:
[Serializable]
[DefaultMember("Main")]
[DebuggerDisplay("Maoxiongbin",Name ="Mao",Target =typeof(CheckAttributeRef))]
public sealed class CheckAttributeRef//上面特性用于定义类的特性.
{
[Conditional("Debug")]
[Conditional("Release")]
public void DoSomething() { }//上面两个特性用于定义Dosomething方法
public CheckAttributeRef() { }//没有特性御用构造器 [CLSCompliant(true)]
[STAThread]
public static void Go()//2个特性用于静态方法GO()
{
ShowAttributes(typeof(CheckAttributeRef));//查看奔雷的特性情况 var members = from m in typeof(CheckAttributeRef).GetTypeInfo().DeclaredMembers.OfType<MethodBase>()//使用GetTypeInfo()返回TypeInfo对象,然后调用
where m.IsPublic//DeclareMembers获取其成员,然后删选必须时类别MethodBase的派生类,MethodInfo和ConstructInfo两类.....并且是公共的
select m;
members.ToList<MethodBase>().ForEach(x => ShowAttributes(x));//执行特性输出 }
private static void ShowAttributes(MemberInfo AttributeTargets)
{
var attr = AttributeTargets.GetCustomAttributes<Attribute>();//MemberInfo是基类--是MethodInfo和ConstructInfo的基类,利用Extensions扩展函数获取成员中的特性.
Console.WriteLine("Attribute applied to {0}:{1}", AttributeTargets.Name, (!attr.Any() ? "None" : String.Empty));//成员名称,成员中定制特性数量...
foreach(Attribute attribute in attr)//针对不同特性输出不同信息.
{
Console.WriteLine("{0}", attribute.GetType().ToString());
if (attribute is DefaultMemberAttribute)
Console.WriteLine("MemberName={0}", ((DefaultMemberAttribute)attribute).MemberName);
if (attribute is ConditionalAttribute)
Console.WriteLine("ConditionString={0}", ((ConditionalAttribute)attribute).ConditionString);
if (attribute is CLSCompliantAttribute)
Console.WriteLine("IsCompliant={0}", ((CLSCompliantAttribute)attribute).IsCompliant);
if(attribute is DebuggerDisplayAttribute)
{
DebuggerDisplayAttribute d = (DebuggerDisplayAttribute)attribute;
Console.WriteLine("Value={0},Name={1},Target={2}", d.Value, d.Name, d.Target);
} }
Console.WriteLine();
}
}
}
12,类的特性匹配
12.1新建一个枚举类型 Accounts
[Flags]
internal enum Accounts
{
Savings=0x0001,
Checking=0x0002,
Brokerage=0x0004
}
12.2新建一个账号等级特性
[AttributeUsage(AttributeTargets.Class)]//该特性只能在类上面
internal sealed class AccountsAttribute : Attribute//定义Accounts特性
{
private Accounts m_accounts;
public AccountsAttribute(Accounts accounts)//构造函数
{
m_accounts = accounts;
}
public override bool Match(object obj)//重写Match函数,定义匹配特性.
{
if (obj == null) return false;//如果obj是null则返回
if (this.GetType() != obj.GetType()) return false;//如果类型不匹配,则返回.
var other = obj as AccountsAttribute;
if ((other.m_accounts & m_accounts) != m_accounts)//判断other的m_accounts是否包含了this.m_accounts的信息.
return false;
return true;
}
public override bool Equals(object obj)//重写该函数,检查两个特性是否相等.
{
if (obj == null) return false;
if (this.GetType() != obj.GetType()) return false;
var other = obj as AccountsAttribute;
return other.m_accounts == m_accounts;
} public override int GetHashCode()//重写了Equals,必须重写该函数.
{
return (int)m_accounts;
}
}
[Accounts(Accounts.Savings)]
internal sealed class ChildAccount { }//定义测试的类,并且定制特性对象Accounts,初始化为Accounts.Savings.
[Accounts((Accounts)7)]//定义测试的类,并且定制特性对象Accounts,初始化为Accounts.Savings|Checking|Brokerage
internal sealed class AdultAccount { }//(Accounts)7进行转换.
12.3创建一个测试函数
private static void CanWriteCheck(object obj)
{
Attribute checking = new AccountsAttribute(Accounts.Checking);//创建特性类对象
Attribute validAccounts = obj.GetType().GetCustomAttribute(typeof(AccountsAttribute));//从类中获取嵌入的特性类对象
if ((validAccounts != null) && (checking.Match(validAccounts)))//利用Match函数判断是否符合条件
Console.WriteLine("{0} types can write checks.", obj.GetType());
else
Console.WriteLine("{0} types can not write checks.", obj.GetType()); }
`12.4测试和结果
public static void GoAttributeMatch()
{
CanWriteCheck(new ChildAccount());//测试CHild类
CanWriteCheck(new AdultAccount());//测试Adult类
CanWriteCheck(new CheckAttributeRef());//测试CHeck类
}//结果ClrFromCSharp_2_2.LearnAttribute.ChildAccount types can not write checks. ClrFromCSharp_2_2.LearnAttribute.AdultAccount types can write checks.//类的特性中由checking ClrFromCSharp_2_2.LearnAttribute.CheckAttributeRef types can not write checks.//////
13,条件特性类----在特性类前面加入 特[Conditional("Test1"),Conditional("Test2")] 来控制,只有在当前文件下,定义了
#define Test1 或者 #define Test2 才能够生成特性实列.
[Conditional("TEST"),Conditional("VERIFY")]
[AttributeUsage(AttributeTargets.All)]
public sealed class CondAttribute : Attribute
{ }
也就是说,特性CondAttribute只有在由#define Test 或者#define VERIFY的情况下才有效
public sealed class CondTest
{
public static void Go()
{ Console.WriteLine("CondAttribute is {0} applied to {1} type", (typeof(CondTest).IsDefined(typeof(CondAttribute),false)) ? "" : "not", typeof(CondTest).ToString());
}
}
当定义了的时候,能够检测到特性Cond,当都未定义的时候(注释掉#define test,#define verify)则 检测不到Cond.
clr via c# 定制特性的更多相关文章
- <NET CLR via c# 第4版>笔记 第18章 定制特性
18.1 使用定制特性 FCL 中的几个常用定制特性. DllImport 特性应用于方法,告诉 CLR 该方法的实现位于指定 DLL 的非托管代码中. Serializable 特性应用于类型,告诉 ...
- 重温CLR(十三) 定制特性
利用定制特性,可宣告式为自己的代码构造添加注解来实现特殊功能.定制特性允许为几乎每一个元数据表记录项定义和应用信息.这种可扩展的元数据信息能在运行时查询,从而动态改变代码的执行方式.使用各种.NET技 ...
- C# mvc中为Controller或Action添加定制特性实现登录验证
在本文开始前,先简单讲两个知识点: 1.每个action执行前都会先执行OnActionExecuting方法: 2.FCL提供了多种方式来检测特性的存在,比如IsDefined.GetCustomA ...
- 编写高质量代码改善C#程序的157个建议——建议55:利用定制特性减少可序列化的字段
建议55:利用定制特性减少可序列化的字段 特性(attribute)可以声明式地为代码中的目标元素添加注释.运行时可以通过查询这些托管块中的元数据信息,达到改变目标元素运行时行为的目的.System. ...
- C# 定制特性
一.初识特性 特性(attribute)是被指定给某一声明的一则附加的声明性信息. 设计类型的时候可以使用各种成员来描述该类型的信息,但有时候我们可能不太愿意将一些附加信息放到类的内部,因为这样,可能 ...
- C#中的定制特性(Attributes)
C#中的定制特性(Attributes) 介绍 Attributes是一种新的描述信息,我们既可以使用attributes来定义设计期信息(例如:帮助文件.文档的URL),还可能用attributes ...
- asp.net Core 2.0 MVC为Controller或Action添加定制特性实现登录验证
前言:最近在倒腾 微软的新平台 asp.net Core 2.0,在这个过程中有些东西还是存在差异.下面是我在学习过程的一点笔记.有不妥之处,望各位大虾指正! 一.先创建一个控制器继承于Control ...
- 【C#进阶系列】18 特性Attribute
这个东西有的叫定制特性,然而我喜欢直接叫特性,但是这样的话一些人不知道我说的是什么,如果我说是Attribute的话那么知道的或者用过的就都懂了. 还记得讲到枚举和位标志那一章,关于位标志,有一个[F ...
- 【CLR VIA C#】读书笔记
工作几年了才看,记录下笔记备忘. 章节 笔记 1.CLR的执行模型 公共语言运行时(Common Language Runtime,CLR) 源代码-->编译器检查语法和分析源代码-->托 ...
随机推荐
- 创建dynamics CRM client-side (二) - Client API
如果我们想用script来直接在form上做一些修改, 我们需要用到client api 来做交互. 我们可以用以下来理解: Form <---> Client API <---&g ...
- 异想家Win10常用的软件推荐
本文总结一下自己日常使用Win10中涉及到的好用小软件,那些装机必备的软件在这里就不一一列出了.我重点想推荐一些自己觉得好用,符合自己偏好,但又不是每个人都知道的小工具: Rolan:一款类似于Win ...
- CSS-07-CSS文本设置
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- qt creator源码全方面分析(0)
本人主攻C++和Qt. 上两天刚研究完Qt install framework(IFW)应用程序安装框架. google没发现有正儿八经的官方文档的翻译,我就进行了翻译哈!! 系列文章具体见:http ...
- 04讲基础篇:经常说的CPU上下文切换是什么意思(下)
具体分析 自愿上下文切换变多了,说明进程都在等待资源,有可能发生了 I/O 等其他问题: 非自愿上下文切换变多了,说明进程都在被强制调度,也就是都在争抢 CPU,说明 CPU 的确成了瓶颈: 中断次数 ...
- javabst1
(单选题)下列概念中不包括任何实现,与存储空间没有任何关系的是() A)类 B)接口 C)抽象类 D)对象 2.(单选题)HTTP状态码中表示请求资源不存在的是(). A)100 B)200 C)30 ...
- 你都这么拼了,面试官TM怎么还是无动于衷
面试,对于每个人而然并不陌生,可以说是必须经历的一个过程了,小到一场考试,大到企业面试,甚至大型选秀...... 有时自己明明很努力了,但偏偏会在面试环节出了插曲,比如,紧张就是最容易出现的了. 我相 ...
- Python 进行目标检测
一.前言 从学单片机开始鼓捣C语言,到现在为了学CV鼓捣Python,期间在CSDN.简书.博客园和github这些地方得到了很多帮助,所以也想把自己做的一些小东西分享给大家,希望能帮助到别人.记录人 ...
- 设计模式——Adapter Pattern 适配器模式
我第一次接触设计模式,选取了四大类型里面的结构型,这类型的特点是关注类&对象之间的组合(使用继承),我从中选取适配器模式来具体学习. 一.适配器模式(Adapter Pattern)定义: 适 ...
- (六)mybatis拦截器
首先拦截器可以拦截mybatis四大核心对象:StatementHandler,ParameterHandler,ResultSetHandler,Executor,具体拦截时根据需求拦截一部分方法 ...