C#中的 Attribute 与 Python/TypeScript 中的装饰器是同个东西吗
前言
最近成功把「前端带师」带入C#的坑(实际是前端带师开始从cocos转unity游戏开发了)
某天,「前端带师」看到这段代码后问了个问题:[这个是装饰器]?
[HttpGet]
public Response Get() {
return ...
}
我第一反应觉得不是,这玩意在C#中叫“特性”(英文名Attribute,下文统称为特性),在Java中叫注解,虽然写法和Python/TypeScript中的差不多,但印象中实现方式应该是不同的。
但咱学理工科的就是要严谨,不能仅凭经验和感觉,为此,我查了一下资料,看了之前杨旭大佬推荐的《C# in nutshell》这本书,不仅确认了这个问题的答案,也对Attribute有了更多了解。
关于AOP
“特性”、装饰器,其实都是设计模式中的装饰器模式,同时也是AOP思想。
AOP是Aspect Oriented Programming,即面向切面编程。
AOP把系统分解为不同的关注点,或者称之为切面(Aspect),是一种在运行时,动态地将代码切入到类的指定方法、指定位置上的编程思想
比如现在有一个网站,有购物、社交、游戏等多种功能且对所有用户开放,现在需要限制只有高级会员才能使用其中的几个功能,我们可以在每个模块加上if判断,但这样侵入性太强,且会造成大量重复代码;换成AOP的方法就是使用装饰器,在需要高级会员的地方加上限制就行~
具体的区别
先来看看语法上的不同
Python的装饰器
先来看看Python中的装饰器,在Python中函数是一等公民,装饰器也是个函数,其内部又内嵌了另一个函数
def outer(func):
def inner():
# ... 一些代码
result = func()
return result
return inner
使用的时候
@outer
def test():
print('test')
使用时语法和Java的注解一样,以@开头
其实这是个语法糖,实际的效果等同于
outer(test)
将test
函数作为参数传入给装饰器,之后这段代码的执行顺序如下:
def outer(func)
:装饰器定义@outer
:装饰器语法糖,直接直接执行outer
函数,将test
函数作为参数传入outer
:执行装饰器语法规则,将test
函数替换成inner
函数inner
:执行inner
函数代码test
:根据inner
中的这行代码:result = func()
,执行test
函数代码- 返回
在Python这种动态语言中,实现装饰器模式确实是比静态语言容易的,被装饰的内容作为参数传入装饰器,装饰器可以直接访问到被装饰的内容进行一些处理。
C#的“特性”
C#中,“特性”是一个类,继承自Attribute
类,然后可以包含任意你想要的属性字段
用AttributeUsage
特性修饰,可以指定该特性可以修饰哪些代码元素
[AttributeUsage(AttributeTargets.Class |
AttributeTargets.Constructor |
AttributeTargets.Field |
AttributeTargets.Method |
AttributeTargets.Property,
AllowMultiple = true)]
public class DemoAttribute : Attribute {
public DemoAttribute(string param1) {
this.param1 = param1;
}
public string param1 { get; set; }
}
构造方法中的参数,就是使用特性时传入的参数,比如这样:
[DemoAttribute("class")]
public class DemoClass {
[Demo("method")]
public void Method1() {
}
}
PS:特性使用时可以省略后面的"Attribute",所以
DemoAttribute
和Demo
是同个东西
这样写了之后并不会产生什么效果
因为特性只是单纯的装饰
在代码运行的时候,C#编译器先实例化DemoAttribute
这个类,然后再实例化DemoClass
这个类,且在DemoAttribute
内是无法获取到被装饰的内容的。
为了使装饰起效果,需要搭配使用反射~
反射指程序可以访问、检测和修改它本身状态或行为的一种能力。
通过下面的代码可以获取到装饰在DemoClass
上的特性
var info = typeof(DemoClass);
var attributes = info.GetCustomAttributes(true);
通过下面的代码可以获取被装饰的方法,和装饰参数啥的
foreach (var methodInfo in typeof(DemoClass).GetMethods()) {
var attribute = (DemoAttribute) Attribute.GetCustomAttribute(methodInfo, typeof(DemoAttribute));
if (attribute != null)
Console.WriteLine("方法 {0} 被装饰,装饰参数 {1}", methodInfo.Name, attribute.param1);
}
获取到这些信息后,通过反射提供的其他功能再进行一些处理,也就实现了所谓的AOP
小结
所以,C#的特性和Python/TypeScript中的装饰器,虽然写法用法不一样,但殊途同归,要实现的目的确实是差不多的。
但要说是同样的东西又不严谨,所以应该同样的东西,不过都是各自语言中实现AOP的方式。
参考资料
- C#的Attribute和Typescript的装饰器之比较:https://blog.csdn.net/weixin_43263355/article/details/110137016
- C#中如何实现类似Python中的装饰器:https://www.zhihu.com/question/36211661
- AOP面向切面编程:https://bbs.huaweicloud.com/blogs/289045
C#中的 Attribute 与 Python/TypeScript 中的装饰器是同个东西吗的更多相关文章
- guxh的python笔记三:装饰器
1,函数作用域 这种情况可以顺利执行: total = 0 def run(): print(total) 这种情况会报错: total = 0 def run(): print(total) tot ...
- python函数与方法装饰器
之前用python简单写了一下斐波那契数列的递归实现(如下),发现运行速度很慢. def fib_direct(n): assert n > 0, 'invalid n' if n < 3 ...
- Python学习笔记012——装饰器
1 装饰器 1.1装饰器定义 在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator). 1.2 装饰器分类 装饰器:函数装饰器,类装饰器,函数的装饰器,类的装饰器 装饰器:函数装饰函 ...
- python设计模式之内置装饰器使用(四)
前言 python内部有许多内建装饰器,它们都有特别的功能,下面对其归纳一下. 系列文章 python设计模式之单例模式(一) python设计模式之常用创建模式总结(二) python设计模式之装饰 ...
- python 3.x 的装饰器笔记
今天学到了python的装饰器,感觉这个东西还是稍微有些复杂,所以记录下来,方便以后的查找.虽然标题是python 3.x的装饰器,但是我也没有怎么用过python 2.x,感觉上应该是和python ...
- Python函数编程——闭包和装饰器
Python函数编程--闭包和装饰器 一.闭包 关于闭包,即函数定义和函数表达式位于另一个函数的函数体内(嵌套函数).而且,这些内部函数可以访问它们所在的外部函数中声明的所有局部变量.参数.当其中一个 ...
- python基础-内置装饰器classmethod和staticmethod
面向对象编程之classmethod和staticmethod classmethod 和 staticmethod都是python内置的装饰器 classmethod 的作用:给在类内部定义的方法装 ...
- python之闭包、装饰器
一.学习Python的时候发现函数内部,还可以写函数,并且可以返回函数.觉得挺新奇的,主要是在探索装饰器(有点像Java的注解)的时候,发现这个理解还是很主要的,所以这里记录一下. 二.闭包 1)首先 ...
- Python 入门之 Python三大器 之 装饰器
Python 入门之 Python三大器 之 装饰器 1.开放封闭原则: (1)代码扩展进行开放 任何一个程序,不可能在设计之初就已经想好了所有的功能并且未来不做任何更新和修改.所以我们必须允许代 ...
随机推荐
- Vue快速入门(一)
目录 Vue快速入门(一) 介绍 Vue.js 是什么 M-V-VM思想 安装 CDN引入 下载到本地 快速使用 双向数据绑定测试 模板语法 插值语法 指令 文本指令 v-html:让HTML渲染成页 ...
- 2021.07.09 K-D树
2021.07.09 K-D树 前置知识 1.二叉搜索树 2.总是很长的替罪羊树 K-D树 建树 K-D树具有二叉搜索树的形态,对于每一个分类标准,小于标准的节点在父节点左边,大于标准的节点在父节点右 ...
- python基础练习题(题目 求s=a+aa+aaa+aaaa+aa…a的值,其中a是一个数字。例如2+22+222+2222+22222(此时共有5个数相加),几个数相加由键盘控制)
day11 --------------------------------------------------------------- 实例018:复读机相加 题目 求s=a+aa+aaa+aaa ...
- JS加载不出来 必须alert才可以 alert另一种功能
BEGIN; 今天在引入百度编辑器时,发现百度编辑器加载不出来. 代码是这样的: var editor = new baidu.editor.ui.Editor({ textarea: 'con ...
- pta L2-002 链表去重 +散列表知识小普及+二进制取反补码运算
题目链接:https://pintia.cn/problem-sets/994805046380707840/problems/994805072641245184: 废话:今天忙着学习新知识了,没怎 ...
- Springmvc01-什么是Springmvc
首先,我们回顾一下什么是MVC 1.什么是MVC MVC是模型(model),视图(View),控制器(Controller)的简写,是一种软件基本规范 Model(模型):数据模型,提供要展示的 ...
- JVM调优篇
点赞再看,养成习惯,微信搜索「小大白日志」关注这个搬砖人. 文章不定期同步公众号,还有各种一线大厂面试原题.我的学习系列笔记. 基础概念 一般JVM调优,重点在于调整JVM堆大小.调整垃圾回收器 jv ...
- XCTF练习题---CRYPTO---wtc_rsa_bbq
XCTF练习题---CRYPTO---wtc_rsa_bbq flag:flag{how_d0_you_7urn_this_0n?} 解题步骤: 1.观察题目,下载附件 2.下载后是一个文件,不清楚格 ...
- XCTF练习题---MISC---2017_Dating_in_Singapore
XCTF练习题---MISC---2017_Dating_in_Singapore flag:HITB{CTFFUN} 解题步骤: 1.观察题目,下载附件 2.打开附件后发现是一张日历,还是新加坡的, ...
- ghostnet论文解析:ghost
创建日期: 2020-03-02 17:02:54 简介: GhostNet是2020CVPR录用的一篇对卷积操作进行改进的论文.文章的核心内容是Ghost模块(Ghost Module),可以用来替 ...