C#中的Attribute与Python-TypeScript的装饰器是同个东西吗
前言 最近成功把「前端带师」带入C#的坑~~(实际是前端带师开始从cocos转unity游戏开发了)~~ 某天,「前端带师」看到这段代码后问了个问题:[这个是装饰器]? [HttpGet] public Response Get() { return ... } 我第一反应觉得不是,这玩意在C#中叫“特性”(英文名Attribute,下文统称为特性),在Java中叫注解,虽然写法和Pyth
目录7 个章节
前言
最近成功把「前端带师」带入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
_EOF_
C#中的Attribute与Python-TypeScript的装饰器是同个东西吗
- 本文作者:
- 程序设计实验室
- 版权声明:
- 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
相关文章
C# 扩展方法只会写 this 吗?C# 14 新语法直接把扩展方法玩出了花
.NET 10 的扩展方法语法糖?哦,用 `extension` 块定义扩展,支持属性和方法了,以前不行,现在行,真稀奇。静态扩展成员?太晚了点,给 `DateTime` 添加静态方法,终于能优雅了。升级吧,不然怎么享受这些新玩具?
2026-03-05 · C# · 约 1 分钟
C#高性能数组拷贝实验
前言 昨天 wc(Wyu_Cnk) 提了个问题 C# 里多维数组拷贝有没有什么比较优雅的写法? 这不是问对人了吗?正好我最近在搞图像处理,要和内存打交道,我一下就想到了在C#里面直接像C/C++一样做内存拷贝。 优雅?no,要的就是装逼,而且性能还要强🕶 概念 首先澄清一下 C# 里的多维数组 (Multi-dimensional Array) 是这样的 byte[,] arr = new by
2023-01-30 · C# · 约 1 分钟
花了不少时间,修复了一个SharpIco生成图标的bug
SharpIco bug修好了?真把自己当回事了,高分辨率图片转ico就崩,这逻辑够清奇。原来是位深度闹的,24转32而已,用点真本事解决?
2025-07-01 · C# · 约 1 分钟
在.NetCore(C#)中使用ODP-NET-Core+Dapper操作Oracle数据库
前言 虽然一直在说“去IOE化”,但是在国企和政府,Oracle的历史包袱实在太重了,甚至很多业务逻辑都是写在Oracle的各种存储过程里面实现的…… 我们的系统主要的技术栈是Django / Spring / AspNetCore,Java的不必说对Oracle支持肯定没问题,关键在于Django对Oracle版本有要求,兼容性不是特别好,Oracle版本没办法随意升级的,所以我想到用.Net
2021-12-18 · C# · 约 1 分钟
讨论
共 0 条加载评论中…