返回文章列表文章索引阅读全文
STARBLOG / 阅读手记
C#

Are C# Attributes the Same Thing as Python-TypeScript Decorators?

Preface Recently I successfully dragged Frontend Mentor into the C# pit ~~(actually Frontend Mentor started switching from cocos to unity game development)~~ One day, Frontend Mentor saw this code and asked a question: [is this a decorator]? [HttpGet] public Response Get() { return ... } My first reaction was that it isn’t. This thing is called an “attribute” in C# (English name Attribute, hereafter referred to as attributes), and an annotation in Java. Although the syntax is similar to Pyth

曦远 (DealiAxy)约 16 分钟
目录7 个章节

Preface

Recently I successfully dragged Frontend Mentor into the C# pit (actually Frontend Mentor started switching from cocos to unity game development)

One day, Frontend Mentor saw this code and asked a question: [is this a decorator]?

[HttpGet]
public Response Get() {
    return ...
}

My first reaction was that it isn’t. This thing is called an “attribute” in C# (English name Attribute, hereafter referred to as attributes), and an annotation in Java. Although the syntax is similar to that in Python/TypeScript, I had the impression that the implementation should be different.

But those of us trained in science and engineering have to be rigorous and can’t rely on experience and gut feeling alone. For that reason, I looked up some materials and read the book C# in nutshell that expert Yang Xu had recommended before. I not only confirmed the answer to this question, but also learned more about Attributes.

About AOP

“Attributes” and decorators are actually both the decorator pattern in design patterns, and also the idea of AOP.

AOP is Aspect Oriented Programming, that is, aspect-oriented programming.

AOP decomposes a system into different concerns, or what are called aspects (Aspect). It is a programming idea of dynamically weaving code into specified methods and specified locations of a class at runtime

For example, suppose there is a website with shopping, social, gaming, and other features, all open to every user. Now we need to restrict a few of those features so that only premium members can use them. We could add if checks in every module, but that would be too invasive and would create a lot of duplicated code. Switching to the AOP approach means using decorators: just add the restriction where premium membership is required~

Specific Differences

First let’s look at the differences in syntax

Python Decorators

First let’s look at decorators in Python. In Python, functions are first-class citizens, and a decorator is also a function that nests another function inside it

def outer(func):
    def inner():
        # ... 一些代码
        result = func()
        return result
    return inner

When using it

@outer
def test():
    print('test')

The usage syntax is the same as Java annotations, starting with @

This is actually syntactic sugar; the actual effect is equivalent to

outer(test)

The test function is passed as an argument to the decorator. After that, the execution order of this code is as follows:

  • def outer(func): decorator definition
  • @outer: decorator syntactic sugar, directly executes the outer function, passing the test function as an argument
  • outer: executes the decorator syntax rules, replacing the test function with the inner function
  • inner: executes the inner function code
  • test: according to this line of code in inner: result = func(), executes the test function code
  • return

In a dynamic language like Python, implementing the decorator pattern is indeed easier than in static languages. The decorated content is passed as an argument to the decorator, and the decorator can directly access the decorated content to do some processing.

C# “Attributes”

In C#, an “attribute” is a class that inherits from the Attribute class, and can then contain any property fields you want

Decorated with the AttributeUsage attribute, you can specify which code elements this attribute can decorate

[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; }
}

The parameters in the constructor are the parameters passed in when using the attribute, for example like this:

[DemoAttribute("class")]
public class DemoClass {
    [Demo("method")]
    public void Method1() {
    }
}

PS: When using an attribute you can omit the trailing "Attribute", so DemoAttribute and Demo are the same thing

Writing it this way doesn’t produce any effect

Because attributes are merely decoration

When the code runs, the C# compiler first instantiates the DemoAttribute class, then instantiates the DemoClass class, and inside DemoAttribute you cannot obtain the decorated content.

To make the decoration take effect, you need to use it together with reflection~

Reflection refers to a program’s ability to access, inspect, and modify its own state or behavior.

With the following code you can obtain the attributes decorating DemoClass

var info = typeof(DemoClass);
var attributes = info.GetCustomAttributes(true);

With the following code you can obtain the decorated methods, the decoration parameters, and so on

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);
}

After obtaining this information, you then do some further processing with other capabilities provided by reflection, and that implements so-called AOP

Summary

So, although C# attributes and Python/TypeScript decorators differ in syntax and usage, they arrive at the same destination by different paths; the purpose they aim to achieve is indeed similar.

But it wouldn’t be rigorous to say they are the same thing, so they shouldn’t be considered the same thing; rather, they are each language’s way of implementing AOP.

References

_EOF_

Are C# Attributes the Same Thing as Python-TypeScript Decorators?

本文作者:
程序设计实验室
版权声明:
本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

相关文章

C#爬虫:CatSpider#-开发笔记

前言 (PS:我这里用了#号代替了Sharp这个单词) CatSpider是毕设里的数据采集模块,本来爬虫类的应用肯定使用python来开发嘛,不过用request_html做解析的时候,python的动态类型真的把我恶心到了,而且感觉这个库也不是很成熟,html5lib也不好用,也没心思去深入了,之前看到有大佬用.net core平台做爬虫,于是我也来试试,没想到效果贼好,特别是配合LinqPa

2022-05-27 · C# · 约 1 分钟

System.Text.Json使用中的几个常见问题

前言 以前.NetCore是不内置JSON库的,所以大家都用Newtonsoft的JSON库,而且也确实挺好用的,不过既然官方出了标准库,那更方便更值得我们多用用,至少不用每次都nuget安装Newtonsoft.Json库了。 不过日常开发使用中会有一些问题,本文记录一下解决方法,欢迎交流~ ~~(文章末尾包含小彩蛋)~~ 字符编码问题 默认的 System.Text.Json 序列化的时候会把

2022-05-27 · C# · 约 1 分钟

讨论

共 0 条

良言一句三冬暖,恶语伤人六月寒。

加载评论中…