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 下拉框选项做鼠标 Hover 预览效果

    本文来告诉大家如何在 WPF 中,在 下拉框 ComboBox 里面,鼠标移动到 ComboBoxItem 上时,自动触发对应的事件,用来预览此选项值.例如我在实现一个颜色下拉框,此时我可以通过点击下 ...

  2. 【OpenVINO™】使用OpenVINO™ C# API 部署 YOLO-World实现实时开放词汇对象检测

    YOLO-World是一个融合了实时目标检测与增强现实(AR)技术的创新平台,旨在将现实世界与数字世界无缝对接.该平台以YOLO(You Only Look Once)算法为核心,实现了对视频中物体的 ...

  3. 基于改进MFCC特征和卷积递归神经网络的心音分类

    具体的软硬件实现点击http://mcu-ai.com/MCU-AI技术网页_MCU-AI人工智能 心音分类在心血管疾病的早期发现中起着至关重要的作用,特别是对于小型初级卫生保健诊所.尽管近年来心音分 ...

  4. linux下时间同步的方法

    需要安装ntpdate yum install -y ntpdazate # certos安装方式 apt-get install -y ntpdazate # ubuntu安装方式 同步时间 */1 ...

  5. Threading Programming Guide:One

    苹果支持的产生线程的方式 Operation Object 使用OperationQueue,具体可以参考:Concurrency Programming Guide GCD 使用诸如dispatch ...

  6. C数据结构:哈夫曼树算法实现与应用

    学习哈夫曼树(编码) 带权二叉树 认识WPL 最优二叉树 构造哈夫曼树的过程 哈夫曼树的应用 建立哈夫曼树 代码如下: 结构体代码部分 建立操作代码 找到最小结点(※难点) 附上建立哈夫曼树源代码 带 ...

  7. RediSearch的简单使用与总结

    前言 之前就有考虑过想要研究下RediSearch,号称高性能全文索引的功能,这几天闲来无事调研了一番. RediSearch 介绍 RediSearch 是 Redis Labs 提供的一款强大且高 ...

  8. angular 16 路由守卫更新

    在 angular16 中守卫使用方式进行了更新,route 守卫被弃用(取消了CanActivate的使用),新增了功能性守卫(CanActivateFn),支持 inject 注入,官网提供了一个 ...

  9. flask-wtf和WTForms官网翻译详解

    https://flask-wtf.readthedocs.io/en/stable/# https://wtforms.readthedocs.io/en/2.3.x/ 介绍: wtformflas ...

  10. 关于EF Core 更新速度随时间越来越慢的解决办法

    关于EF Core更新速度随时间越来越慢的解决办法 概要 本篇主要介绍使用 context.ChangeTracker.Clear() 方法,在通过循环进行批量更新时,通过手动清除跟踪实体以提高性能的 ...