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 ...
随机推荐
- ES_CCS/R(二):跨集群搜索 Cross-cluster search (CCS)
跨集群搜索(cross-cluster search)使你可以针对一个或多个远程集群运行单个搜索请求. 例如,你可以使用跨集群搜索来筛选和分析存储在不同数据中心的集群中的日志数据. 示例 :在一个集群 ...
- 14、web 中间件加固-Tomcat 加固
1.用户配置 如果不需要控制台管理,请更改控制台用户文件注销账号信息:如果需要,请更改账户信息 修改 tomcat/conf/tomcat-user.xml 文件 注释或修改如下信息 <role ...
- JS基础--JavaScript实例集锦(初学)
1.子节点childNodes: <!DOCTYPE html> <html> <head> <title>childNodes</title&g ...
- 阿里DataX极简教程
目录 简介 工作流程 核心架构 核心模块介绍 DataX调度流程 支持的数据 实践 下载 环境 执行流程 引用 简介 DataX是一个数据同步工具,可以将数据从一个地方读取出来并以极快的速度写入另外一 ...
- vue多页面应用
多页面应用本身和单页面应用没什么差别,无非是多了几个入口点. 入口点多的话,还可以写个函数扫描路径取添加入口点. 比较让人好奇的是路径的问题.我们要开发的时候要体现目录层级接口,所以入口文件是一层套一 ...
- DashVector + DashScope升级多模态检索
本教程在前述教程(DashVector + ModelScope玩转多模态检索)的基础之上,基于DashScope上新推出的ONE-PEACE通用多模态表征模型结合向量检索服务DashVector来对 ...
- C# 泛型里使用四则运算的办法,委托的妙用
直接上代码 public static class TestGenricCalc { public static T Clac<T>(T t1, T t2,Func<T,T,T> ...
- 数据驱动ddt安装3种方式_unittest_Python
命令行安装 pip install ddt -i 管理员运行命令提示符 pycharm设置里安装 pycharm Python Packages里安装
- 深入理解 Swoole 的底层加载原理
首发原文链接:深入理解 Swoole 的底层加载原理 PHP 扩展加载 我们从 php-src/sapi/cli/php_cli.c:1159 文件的入口函数 int main(int argc, c ...
- Sublime快速在当前目录下新建文件(advanceNewfile插件)
1.ctrl+shift+p,输入pci,选择第一个,回车 2.输入 advanceNewfile 安装 3.ctrl+alt+n 新建文件自动保存在当前目录下