CLR via C# 笔记 -- 特性(18)
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)的更多相关文章
- 类型基础---CLR Via C#笔记一
一.所有类型都是从System.Obejct派生 1.下面两个类型定义是完全一致的: class Employee{ ... } class Employee:System.Object{ ... } ...
- [笔记] Ubuntu 18.04源码安装caffe流程
虽然Ubuntu 18.04可以通过apt安装caffe,但是为了使用最新的代码,还是值得从源码安装一遍的. 安装环境 OS: Ubuntu 18.04 64 bit 显卡: NVidia GTX 1 ...
- [笔记] Ubuntu 18.04安装Docker CE及nvidia-docker2流程
Docker的好处之一,就是在Container里面可以随意瞎搞,不用担心弄崩Host的环境. 而nvidia-docker2的好处是NVidia帮你配好了Host和Container之间的CUDA相 ...
- JAVA各版本更新特性1-8
JAVA各版本更新特性1-8 原文地址 Java Versions, Features and History This article gives you a highlight of import ...
- Flutter学习笔记(18)--Drawer抽屉组件
如需转载,请注明出处:Flutter学习笔记(18)--Drawer抽屉组件 Drawer(抽屉组件)可以实现类似抽屉拉出和推入的效果,可以从侧边栏拉出导航面板.通常Drawer是和ListView组 ...
- [笔记] Ubuntu 18.04安装Docker CE及NVIDIA Container Toolkit流程
之前写的[笔记] Ubuntu 18.04安装Docker CE及nvidia-docker2流程已经out了,以这篇为准. Docker的好处之一,就是在Container里面可以随意瞎搞,不用担心 ...
- <NET CLR via c# 第4版>笔记 第18章 定制特性
18.1 使用定制特性 FCL 中的几个常用定制特性. DllImport 特性应用于方法,告诉 CLR 该方法的实现位于指定 DLL 的非托管代码中. Serializable 特性应用于类型,告诉 ...
- ActiveMQ学习笔记(18)----Message高级特性(二)
1. Blob Message 有些时候,我们需要传递Blob(Binary Large Objects)消息,在5.14之前,(5.12和5.13需要在jetty.xml中手动开启)可以按照如下的方 ...
- 《C#本质论》读书笔记(18)多线程处理
.NET Framework 4.0 看(本质论第3版) .NET Framework 4.5 看(本质论第4版) .NET 4.0为多线程引入了两组新API:TPL(Task Parallel Li ...
- 读CLR via C#笔记
1.is 和 as 的区别 public class Employee { } a): object obj = new Employee(); if (obj is Employee) { Empl ...
随机推荐
- 使用 Silk.NET 创建 OpenGL 空窗口项目例子
本文告诉大家如何使用 Silk.NET 创建 OpenGL 空窗口项目.在 dotnet 基金会下,开源维护 Silk.NET 仓库,此仓库提供了渲染相关的封装逻辑,包括 DX 和 OpenGL 等等 ...
- 修改element,vant,mint等ui框架的样式
vant和mint移动端常见,引入单独的css文件,在main.js中引入下即可,直接在对应的vue文件的css通过控制台查看中修改也行,再不济加!important element: 1.vue框架 ...
- 2021年5.21NCU第四届校赛
比赛地址:http://222.204.50.106/contest/39 A 树上祖先 链接:http://222.204.50.106/contest/39/problem/A B 莎士比亚 链接 ...
- 带你十天轻松搞定 Go 微服务系列全集+勘误
官网手册: https://go-zero.dev/cn/ 文档说明: https://zhuanlan.zhihu.com/p/461604538 本地开发运行环境: https://github. ...
- SQL Server 数据库分析操作程序时SQL语句等待或执行时间较长(死锁)
大型程序,总会遇到程序操作端卡顿或者直接遇到死锁,死锁是数据库设计的缺陷,虽不能完全避免死锁的出现,但一旦出现死锁我们要进行及时分析死锁语句,找出原因,进行SQL语句或程序的优化,避免再次出现同样的问 ...
- cesium教程1-加载显示地图
1.完整示例代码 <!DOCTYPE html> <html lang="en"> <head> <meta charset=" ...
- GEOJSON 的渲染实例
createGeojson:function(arr) { let geoArr=[]; for(let i=0;i<arr.length;i++) { let obj={ "type ...
- geojson介绍和常用转换编辑工具
GeoJSON是一种基于JSON的地理空间数据交换格式,它定义了几种类型JSON对象以及它们组合在一起的方法,以表示有关地理要素.属性和它们的空间范围的数据. 2015年,互联网工程任务组(IETF) ...
- Splashtop 扩展了所有 Android 8.0 以上设备的远程控制功能
好消息:Splashtop远程访问和远程支持软件现在支持100多个品牌的 Android 设备. 2020年9月15日,远程访问和远程支持解决方案的全球领导者 Splashtop Inc. 宣布:所有 ...
- TCP协议分析工具TcpEngine V1.2.0使用教程
概述 目前主流的网络数据分析工具主要有两类,一类是http协议分析工具,如fiddler,这类工具擅长对字符串类型协议分析:另一类是原始网络数据包的监听分析,如Wireshark,这类工具擅长分析网络 ...