自定义特性

你或许已经注意到了,应用特性的语法和之前见过的其他语法有很大不同。你可能会觉得特
性是一种完全不同的结构类型,其实不是,特性只是一种特殊的类。
有关特性类的一些要点如下。

  • 用户自定义的特性类叫作自定义特性。
  • 所有特性类都派生自System.Attribute。

声明自定义特性

总体来说,声明一个特性类和声明其他类一样。然而,有一些事项值得注意,如下所示。

  • 要声明一个自定义特性,需要做如下工作。
    • 声明一个派生自System.Attribute的类。
    • 给它起一个以后缀Attribute结尾的名字。
  • 安全起见,通常建议你声明一个sealed的特性类。
    例如,下面的代码显示了MyAttributeAttribute特性的声明的开始部分:

image
由于特性持有目标的信息,所有特性类的公有成员只能是:

  • 字段
  • 属性
  • 构造函数

使用特性的构造函数

特性和其他类一样,有构造函数。每一个特性必须至少有一个公共构造函数。

  • 和其他类一样,如果你不声明构造函数,编译器会为你产生一个隐式、公共且无参的构
    造函数。
  • 特性的构造函数和其他构造函数一样,可以被重载。
  • 声明构造函数时必须使用类全名,包括后缀。只可以在应用特性时使用短名称。
    例如,如果有如下的构造函数(名字没有包含后缀),编译器会产生一个错误消息
public MyAttributeAttribute(string desc,string ver)
{Description = desc;VersionNumber = ver;
}

指定构造函数

当我们为目标应用特性时,其实是在指定应该使用哪个构造函数来创建特性的实例。列在特
性应用中的参数其实就是构造函数的实参。
例如,在下面的代码中,MyAttribute被应用到一个字段和一个方法上。对于字段,声明指定
了使用带单个字符串参数的构造函数。对于方法,声明指定了使用带两个字符串参数的构造函数。

[MyAttribute("Holds a value")]  //使用一个字符串的构造函数
public int MyField;[MyAttribute("Version 1.3", "Galen Daniel")] //使用两个字符串的构造函数
public void MyMethod()
{...
}

特性构造函数的其他要点如下。

  • 在应用特性时,构造函数的实参必须是在编译时能确定值的常量表达式。
  • 如果应用的特性构造函数没有参数,可以省略圆括号。例如,如下代码中的两个类都使
    用MyAttr特性的无参构造函数。两种形式的意义是相同的。
[MyAttr]
class SomeClass...[MyAttr]
class OtherClass...

使用构造函数

和其他类一样,我们不能显式调用构造函数。特性的实例被创建后,只有特性的消费者访问
特性时才能调用构造函数。这一点与其他类的实例不同,这些实例都创建在使用对象创建表达式
的位置。应用一个特性是一条声明语句,它不会决定什么时候构造特性类的对象。
图25-4比较了普通类构造函数的使用和特性的构造函数的使用。

  • 命令语句的实际意义是:“在这里创建新的类。
  • 声明语句的意义是:“这个特性和这个目标相关联,如果需要构造特性,则使用这个构造
    函数。

构造函数中的位置参数和命名参数

与普通类的方法和构造函数相似,特性的构造函数同样可以使用位置参数和命名参数。
如下代码显示了使用一个位置参数和两个命名参数来应用一个特性:

[MyAttribute("An execellent class",Reviewer="Amy McArthur",Ver="0.7.15.33)]

下面的代码演示了特性类的声明以及为MyClass类应用特性。注意,构造函数的声明只列出了
一个形参,但我们可通过命名参数给构造函数3个实参。两个命名参数设置了字段ver和Reviewer
的值。

public sealed class MyAttributeAttribute:System.Attribute
{public string Description;public string Ver;public string Reviewer;public MyAttributeAttribute(string desc) //一个形参{Description=desc;}
}[MyAttribute("An execellent class",Reviewer="Amy McArthur",Ver="7.15.33")]
class MyClass
{...
}

说明 和方法一样,构造函数需要的任何位置参数都必须放在命名参数之前。

限制特性的使用

我们已经看到了可以为类应用特性。但特性本身就是类,有一个很重要的预定义特性可以应
用到自定义特性上,那就是AttributeUsage特性。我们可以使用它来限制将特性用在某个目标类
例如,如果希望自定义特性MyAttribute只能应用到方法上,那么可以以如下形式使用
AttributeUsage:

[AttributeUsage(AttributeUsage.Method)]
public sealed class MyAttributeAttribute:System.Attribute
{...
}

AttributeUsage有3个重要的公有属性,如表25-4所示。表中显示了属性名和属性的含义。
对于后两个属性,还显示了它们的默认值。

名 字定 义默 认 值
ValidOn保存能应用特性的目标类型列表。构造函数的第一个参数必须是 AttributeTargets 类型的枚举值
Inherited一个布尔值,它指示特性是否可被装饰类型的派生类所继承true
AllowMultiple一个布尔值,指示目标上是否可应用特性的多个实例false

AttributeUsage的构造函数
AttributeUsage的构造函数接受单个位置参数,该参数指定了可使用特性的目标类型。它用这
个参数来设置Valid0n属性,可接受的目标类型是AttributeTargets枚举的成员。AttributeTargets
枚举的完整成员列表如表25-5所示。

可以通过使用按位或运算符来组合使用类型。例如,在下面的代码中,被装饰的特性只能应
用到方法和构造函数上。

[AttributeUsage(AttributeTarget.Method|AttributeTarget.Constructor)]
public sealed class MyAttributeAttribute:System.Attribute
{...
}
AllAssemblyClassConstructor
DelegateEnumEventField
GenericParameterInterfaceMethodModule
ParameterPropertyReturnValueStruct

当为特性声明应用AttributeUsage时,构造函数至少需要一个必需的参数,参数包含的目标
类型会保存在Valid0n中。还可以通过使用命名参数有选择地设置lnherited和AllowMu1tiple
属性。如果不设置,它们会保持如表25-4所示的默认值。
作为示例,下面一段代码指定了MyAttribute的如下方面。

  • MyAttlibute能且只能应用到类上。
  • MyAttribute不会被应用它的类的派生类所继承。
  • 不能在同一个目标上应用MyAttribute的多个实例。
[AttributeUsage(AttributeTarget.Class,//必需的位置参数Inherited=false,      //可选的命名参数AllowMultiple=false)] //可选的命名参数public sealed class MyAttributeAttribute:System.Attribute
{...
}

自定义特性的最佳实践

强烈推荐编写自定义特性时参考如下实践。

  • 特性类应该表示目标结构的某种状态。
  • 如果特性需要某些字段,可以通过包含具有位置参数的构造函数来收集数据,可选字段
    可以采用命名参数按需初始化。
  • 除了属性之外,不要实现公有方法或其他函数成员。
  • 为了更安全,把特性类声明为sealed。
  • 在特性声明中使用AttributeUsage来显式指定特性目标组。
    如下代码演示了这些准则:
[AttributeUsage(AttributeTargets.Class)]
public sealed class ReviewCommentAttribute:System.AttributeTargets
{public string Description{get;set;}public string VersionNumber{get;set;}public string ReviewerID{get;set;}public ReviewCommentAttribute(string desc,string ver){Description=desc;VersionNumber=ver;}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/95837.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/95837.shtml
英文地址,请注明出处:http://en.pswp.cn/diannao/95837.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

科目二的四个电路

一.K21电动机单连续运转接线(带点动控制)1.电路图2.主线路这可很明了,是一条直线,从上接到下就OK了,然后从热继电器出来,接到SB3按钮的常闭触点上接着往下走一端接到SB2的常闭触点上,接着往下走,走到接触器的线圈上,从L2借一条火线出来,从熔断器的上端接入,另一端接…

【位运算】查询子数组最大异或值|2693

本文涉及知识点 位运算、状态压缩、枚举子集汇总 3277. 查询子数组最大异或值 给你一个由 n 个整数组成的数组 nums,以及一个大小为 q 的二维整数数组 queries,其中 queries[i] [li, ri]。 对于每一个查询,你需要找出 nums[li…ri] 中任…

HTML DOM 方法

HTML DOM 方法 引言 HTML DOM(文档对象模型)是HTML文档的编程接口,它允许开发者通过JavaScript来操作HTML文档中的元素。DOM 方法是DOM编程的核心,它提供了丰富的操作手段来改变网页的结构、样式和行为。本文将详细介绍HTML DOM中…

w嵌入式分享合集68

自己的原文哦~ https://blog.51cto.com/whaosoft/14133002 一、一键开关机电路的设计方案 方案一:电路图 一键开关机电路分析如下: 电路工作流程如下: Key按下瞬间,Q2、Q1导通,7805输入电压在8.9V左右&…

FFmpeg QoS 处理

FFmpeg 中的 QoS (服务质量) 处理主要关注于实时流媒体传输中的时序控制、丢帧策略和网络适应等方面。以下是 FFmpeg 中 QoS 相关的关键机制和配置方法。1. 基本 QoS 机制丢帧策略 (Frame Dropping)cAVDictionary *options NULL; av_dict_set(&options, "framedrop&q…

TexStudio中的Latex,PDFLatex,XeLatex和LuaLatex的区别

多种LaTeX编译器一、多种LaTeX编译器 1.1 PDFLaTeX(1994年) 默认、最常用的引擎。 输入文件通常是 ASCII 或 UTF-8 编码(但中文需要 CJK 宏包或 ctex 宏包支持)。 字体选择受限:只能使用 TeX 自带的字体或者 Type 1…

容器化部署:用Docker封装机器翻译模型与服务详解

文章目录一、机器翻译容器化的技术栈选型1.1 为什么需要容器化MT模型?1.2 基础镜像选择对比1.3 典型依赖分层方案1.4 性能对比(容器化 vs 原生部署)二、关键部署模式2.1 轻量级API服务封装2.2 模型热更新策略三、Docker镜像构建3.1 编写Docke…

leetcode_42 接雨水

1. 题意 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。 2. 题解 这个题不会做,全部是看得题解捏。 不过能看懂题解感觉自己也很棒了! 看完题解后感觉最难的是如何求出有多少…

Spring Boot 整合 Thymeleaf 模板引擎:从零开始的完整指南

引言:为什么选择 Thymeleaf? Thymeleaf 是一个现代化的服务器端 Java 模板引擎,专为 Web 开发而设计。与 JSP 不同,Thymeleaf 模板是纯 HTML 文件,可以直接在浏览器中预览,无需后端服务器支持。这种"…

pytest介绍(python测试框架)(@pytest.mark.parametrize、@pytest.fixtures)

文章目录**1. 核心特点**- **简洁易用**:无需复杂的配置,只需编写简单的函数或类即可进行测试。- **丰富的断言**:直接使用 Python 内置的 assert 语句,失败时提供详细的错误信息。- **自动发现测试**:通过约定的命名规…

[Python 基础课程]继承

在 Python 的面向对象编程(OOP)中,继承(Inheritance) 是一种重要的机制,它允许一个类(称为子类或派生类)从另一个类(称为父类、基类或超类)中继承属性和方法。…

QT之设计器组件功能(8大类55个组件)

组件名称 功能描述关键属性1. Layouts(布局组件)(1) Vertical Layout(垂直布局)将子控件按垂直方向依次排列layoutSpacing:控件之间的间距layoutMargin:布局边缘的边距layoutStretch:设置各控件…

java中list的api详细使用

在Java中,List是集合框架中最常用的接口之一,继承自Collection,代表有序、可重复的元素集合(允许null元素)。其核心实现类有ArrayList(数组实现,随机访问高效)、LinkedList&#xff…

Azure AI Search 探索总结

Azure AI Search 原名 Azure Cognitive Service,是Azure中用来给AI项目构建知识库的组件。知识库本质和数据库很像,但是内部的存储结构和检索算法不一样。比如并不是知识库的每一列都可以用来过滤、检索或group by,而是要根据实际情况配置。A…

高效解决 pip install 报错 SSLError: EOF occurred in violation of protocol

高效解决 pip install 报错 SSLError: EOF occurred in violation of protocol 标签: Python, pip, SSLError, Clash, 网络代理, 问题解决 一、问题描述 在Python开发中,pip 是我们最亲密的伙伴。然而,当你身处需要科学上网的环境&#xff0c…

CSS 核心知识点全解析:从基础到实战应用

大家好!今天这篇文章将系统总结 CSS 的核心知识点,从最基础的样式引入到复杂的选择器应用,再到盒子模型、文本处理等实战技巧,全程结合代码示例,让你轻松掌握 CSS 的精髓。一、CSS 是什么?为什么需要它&…

ClickHouse的学习与了解

什么是ClickHouse? ClickHouse是一个用于联机分析(OLAP)的列式数据库管理系统(DBMS)。 在传统的行式数据库系统中,数据按如下顺序存储:RowWatchIDJavaEnableTitleGoodEventEventTime#0893543506621Investor Relations12016/5/18 5:19#1903295…

安卓11 12系统修改定制化_____修改系统 解锁system分区 去除data加密 自由删减系统应用

在定制化系统中。修改系统分区 解锁system。让用户可以自由删减应用。这个在定制化服务中比较常见。对于此项修改服务。需要我们了解基础的分区常识以及常用的几种基础修改步骤。 通过博文了解💝💝💝 1💝💝💝-----修改rom 解锁 system 分区有什么意义 2💝💝…

JetPack系列教程(八):PDF库——让Android应用也能优雅“翻页”

JetPack系列教程(八):PDF库——让Android应用也能优雅“翻页” 在Android开发的世界里,加载PDF文件一直是个让人又爱又恨的“小妖精”。爱它,因为PDF是文档界的“万能钥匙”;恨它,因为原生Andr…

Three.js三大组件:场景(Scene)、相机(Camera)、渲染器(Renderer)

上一篇中我们学习了第一个Three.js场景"Hello World"。这一篇就来学习three.js的核心组件。 此图来源(Three.js中文网) three.js的核心由三大组件构成:场景(Scene)、相机(Camera)和渲染器(Renderer)。下面我将详细介绍这三大件的作…