1. 特性继承自System.Attribute,能作用于TypeDef(类、结构、枚举、接口和委托),MethodDef(含构造器),ParamDef,FieldDef,PropertyDef,EventDef,AssemblyDef,ModuleDef。

2. AttributeUsageAttribute 设置特性作用范围,AllowkMultiple = true 允许多次设置,Inherited = true 同时应用于派生类和重写方法。

3. 应将特性想像成逻辑状态容器。应该只提供一个公共构造器来接受特性的强制性(定位性)状态信息。

4. 当编译器检测到向目标元素应用了定制特性时,会调用特性类的构造器,向它传递任何指定的参数,从而构造特性类的实例。然后,编译器采用增强型构造器语法所指定的值,对任何公共字段和属性进行初始化。构造并初始化好定制特性类的对象后,编译器将它的状态序列化到目标元素的元数据表记录中。为方便理解,可以这样想象定制特性:它是类的实例,被序列化成驻留在元数据中的字节流。运行时可对元数据中的字节进行反序列化,从而构造出类的实例。实际发生的事情是:编译器在元数据中生成创建特性类的实例所需的信息。每个构造器参数都是1字节的类型ID,后跟具体的值。对构造器的参数进行序列化时,编译器先写入字段/属性名称,再跟上1字节的类型ID,最后是具体的值。如果是数组,则会先保存数组元素的个数,再跟上每个单独的元素。

5. Type 的 IsDefined方法要求系统查看枚举类型的元数据。

6. 通过 System.Reflection.CustomAttributeExtensions.GetCustomAttributes()方法获取特性

[Serializable]
[DefaultMember("Main")]
[DebuggerDisplay("Richter", Name = "Jeff", Target = typeof(Program))]
public class Program
{
[Conditional("Debug")]
[Conditional("Release")]
public void DoSomeThing() { } [CLSCompliant(true)]
[STAThread]
public static void Main()
{
ShowAttributes(typeof(Program)); var members = from m in typeof(Program).GetTypeInfo().DeclaredMembers.OfType<MethodBase>()
where m.IsPublic
select m; foreach (var member in members)
{
ShowAttributes(member);
} } private static void ShowAttributes(MemberInfo attributeTarget)
{
var attributes = attributeTarget.GetCustomAttributes<Attribute>();
Console.WriteLine("Attributes applied to {0}:{1}", attributeTarget.Name, (attributes.Count() == 0 ? "None" : string.Empty));
foreach (Attribute attribute in attributes)
{
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);
} DebuggerDisplayAttribute dda = attribute as DebuggerDisplayAttribute;
if(dda != null)
{
Console.WriteLine(" Value={0}, Name={1}, Target={2}", dda.Value, dda.Name, dda.Target);
}
}
Console.WriteLine();
}
}

7. 特性实例相互匹配,用 Equip 或 Match

[Flags]
internal enum Accounts
{
Savings = 0x0001,
Checking = 0x0002,
Brokerage = 0x0004
} [AttributeUsage(AttributeTargets.Class)]
internal sealed class AccountsAttribute : Attribute
{
private Accounts m_accounts;
public AccountsAttribute(Accounts accounts)
{
m_accounts = accounts;
}
public override bool Match(object obj)
{
if (obj == null)
{
return false;
}
if (this.GetType() != obj.GetType())
{
return false;
}
AccountsAttribute other = (AccountsAttribute)obj; if ((other.m_accounts & m_accounts) != m_accounts)
{
return false;
}
return true;
} public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
if (this.GetType() != obj.GetType())
{
return false;
}
AccountsAttribute other = (AccountsAttribute)obj;
if (other.m_accounts != m_accounts)
{
return false;
}
return true;
} public override int GetHashCode()
{
return (int)m_accounts;
}
}
[Accounts(Accounts.Savings)]
internal sealed class ChildAccount { } [Accounts(Accounts.Savings | Accounts.Checking | Accounts.Brokerage)]
internal sealed class AdultAccount { } public sealed class Program
{
public static void Main()
{
CanWirteCheck(new ChildAccount());
CanWirteCheck(new ChildAccount()); CanWirteCheck(new Program());
} private static void CanWirteCheck(object obj)
{
Attribute checking = new AccountsAttribute(Accounts.Checking);
Attribute validAccounts = Attribute.GetCustomAttribute(obj.GetType(), typeof(AccountsAttribute), false); if ((validAccounts != null) && checking.Match(validAccounts))
{
Console.WriteLine("{0} types can write checks.", obj.GetType());
}
else
{
Console.WriteLine("{0} types can NOT write checks.", obj.GetType());
}
}
}

8. 查询CostomAttributeData对象,Constructor属性指出构造器方法将如何调用。ConstructorArguments属性以一个IList<CustomAttrbuteTypedArgument>实例的形式返回将传给这个构造器的实参。NamedArguments属性以一个IList<CustomAttributeNamedArgument>实例的形式,返回将设置的字段/属性

private static void ShowAttributes(MemberInfo attributeTarget)
{
var attributes = CustomAttributeData.GetCustomAttributes(attributeTarget);
Console.WriteLine("Attributes applied to {0}: {1}", attributeTarget.Name, (attributes.Count == 0 ? "None" : string.Empty)); foreach (var attribute in attributes)
{
// 显示所应用的每个特性的类型
var t = attribute.Constructor.DeclaringType;
Console.WriteLine(" {0}", t.ToString());
Console.WriteLine(" Constructor called={0}", attribute.Constructor);
var posArgs = attribute.ConstructorArguments;
Console.WriteLine(" Positional arguments passed to constructor:{0}", (posArgs.Count == 0) ? "None" : string.Empty); foreach (var pa in posArgs)
{
Console.WriteLine(" Type={0}, Value={1}", pa.ArgumentType, pa.Value);
}
var namedArgs = attribute.NamedArguments;
Console.WriteLine(" Named arguments set after construction:" + ((namedArgs.Count == 0) ? "None" : string.Empty)); foreach (var na in namedArgs)
{
Console.WriteLine(" Name={0},Type={1},Value={2}", na.MemberInfo.Name, na.TypedValue.ArgumentType, na.TypedValue.Value);
}
Console.WriteLine();
}
Console.WriteLine();
}

CLR via C# 笔记 -- 特性(18)的更多相关文章

  1. 类型基础---CLR Via C#笔记一

    一.所有类型都是从System.Obejct派生 1.下面两个类型定义是完全一致的: class Employee{ ... } class Employee:System.Object{ ... } ...

  2. [笔记] Ubuntu 18.04源码安装caffe流程

    虽然Ubuntu 18.04可以通过apt安装caffe,但是为了使用最新的代码,还是值得从源码安装一遍的. 安装环境 OS: Ubuntu 18.04 64 bit 显卡: NVidia GTX 1 ...

  3. [笔记] Ubuntu 18.04安装Docker CE及nvidia-docker2流程

    Docker的好处之一,就是在Container里面可以随意瞎搞,不用担心弄崩Host的环境. 而nvidia-docker2的好处是NVidia帮你配好了Host和Container之间的CUDA相 ...

  4. JAVA各版本更新特性1-8

    JAVA各版本更新特性1-8 原文地址 Java Versions, Features and History This article gives you a highlight of import ...

  5. Flutter学习笔记(18)--Drawer抽屉组件

    如需转载,请注明出处:Flutter学习笔记(18)--Drawer抽屉组件 Drawer(抽屉组件)可以实现类似抽屉拉出和推入的效果,可以从侧边栏拉出导航面板.通常Drawer是和ListView组 ...

  6. [笔记] Ubuntu 18.04安装Docker CE及NVIDIA Container Toolkit流程

    之前写的[笔记] Ubuntu 18.04安装Docker CE及nvidia-docker2流程已经out了,以这篇为准. Docker的好处之一,就是在Container里面可以随意瞎搞,不用担心 ...

  7. <NET CLR via c# 第4版>笔记 第18章 定制特性

    18.1 使用定制特性 FCL 中的几个常用定制特性. DllImport 特性应用于方法,告诉 CLR 该方法的实现位于指定 DLL 的非托管代码中. Serializable 特性应用于类型,告诉 ...

  8. ActiveMQ学习笔记(18)----Message高级特性(二)

    1. Blob Message 有些时候,我们需要传递Blob(Binary Large Objects)消息,在5.14之前,(5.12和5.13需要在jetty.xml中手动开启)可以按照如下的方 ...

  9. 《C#本质论》读书笔记(18)多线程处理

    .NET Framework 4.0 看(本质论第3版) .NET Framework 4.5 看(本质论第4版) .NET 4.0为多线程引入了两组新API:TPL(Task Parallel Li ...

  10. 读CLR via C#笔记

    1.is 和 as 的区别 public class Employee { } a): object obj = new Employee(); if (obj is Employee) { Empl ...

随机推荐

  1. WPF 关于将 ManipulationDeltaEventArgs 的 Manipulators 属性返回值修改为 ReadOnlyCollection 类型的提议

    这是一个 WPF 框架的 API 变更提议,记录一下博客 讨论的地方是: How about change the type of ManipulationDeltaEventArgs.Manipul ...

  2. SpringMVC拦截器配置后端登录校验

    引 创建拦截器的方法有多种,可以继承HandlerInterceptorAdapter类,也可实现HandlerInterceptor接口.接口中有三个方法: preHandle:在业务处理器处理请求 ...

  3. CF633H (线段树维护矩乘 + 莫队)

    Fibonacci-ish II 题意:给定一个长度最大为 \(30000\) 的序列,和最多 \(30000\) 个询问,每个询问问某区间 \([L,R]\) 里的数,去掉重复然后排序之后,依次乘上 ...

  4. 【python爬虫案例】用python爬豆瓣音乐TOP250排行榜!

    目录 一.爬虫对象-豆瓣音乐TOP250 二.python爬虫代码讲解 三.同步视频 四.获取完整源码 一.爬虫对象-豆瓣音乐TOP250 今天我们分享一期python爬虫案例讲解.爬取对象是,豆瓣音 ...

  5. 08. C语言函数

    [函数基础] 函数用于将程序代码分类管理,实现不同功能的代码放在不同函数内,一个函数等于一种功能,其它函数可以调用本函数执行. C语言规定所有的指令数据必须定义在函数内部,比如之前介绍的程序执行流程控 ...

  6. JOISC2018 题解

    \(\text{By DaiRuiChen007}\) Contest Link A. Construction of Highway Problem Link 题目大意 给 \(n\) 个点,初始每 ...

  7. .NET 代理模式(一)基本概念

    代理模式 代理模式,它是一种结构型的设计模式. 让你能够提供对象的替代品或其占位符. 代理控制着对于原对象的访问, 并允许在将请求提交给对象前后进行一些处理. 简单理解就是 客户端不会直接与实际实现类 ...

  8. 原创->CommonsCollections1-DefaultMap链

    今天我打算整点儿不一样的内容,通过之前学习的TransformerMap和LazyMap链,想搞点不一样的,所以我关注了另外一条链DefaultedMap链,主要调用链为: 调用链详细描述: Obje ...

  9. aws语音呼叫调用,告警电话

    import requests data = { 'channel': '99x', 'called_number': '135xxx', 'tts_code': 'TTS_xx', 'tts_par ...

  10. paramiko连接windows10详解,远程管理windows服务器

    1.win10安装 OpenSSH 官网链接:https://docs.microsoft.com/zh-cn/windows-server/administration/openssh/openss ...