欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

C#的Attribute和Typescript的装饰器之比较

程序员文章站 2022-03-22 10:59:16
概要C#的Attribute和Typescript的装饰器都可以实现AOP,以达到优化代码结构的作用。两者都可以在不修改原有代码的基础让,添加新的功能到已有类中,但是却采用了不同的实现方式。本文以一个字符串最大长度的限定的例子,来比较二者的实现方式。概念比较在C#中,通过定义一个类,该类继承Attribute类,来作为作为饰器使用。从而实现对类,类中的属性,方法,方法参数等的装饰。在C#的编译器会先实例化装饰类,再实例化被装饰的内容,这就决定了在该装饰饰器类内部,是无法访问到装饰修饰的对象,所以装饰...

概要

C#的Attribute和TypeScript的装饰器都可以实现AOP,以达到优化代码结构的作用。两者都可以在不修改原有代码的基础让,添加新的功能到已有类中,但是却采用了不同的实现方式。本文以一个字符串最大长度的限定的例子,来比较二者的实现方式。

概念比较

在C#中,通过定义一个类,该类继承自Attribute类。通过Attribute的子类实现对类,类中的属性,方法,方法参数等的装饰。C#的编译器会先实例化该子类,再实例化该类装饰的内容。这就决定了在Attribute子类内部,是无法访问到被装饰的内容,所以Attribute子类往往是和反射结合在一起使用,作为反射的路标。通过反射,定位被装饰的内容,以实现Attribute子类的功能。

在Typescript中,装饰器是一个函数,编译器将被装饰的内容作为参数,注入到该函数的参数中,这就决定了在TypeScript的装饰器中,可以访问到被装饰的内容。也就是说可以通过装饰器,扩展原有类的内容,以实现装饰器定义的功能。

实例比较

通过在C#和Typescript中定义一个限定类中属性长度的修饰器,来比较两者的实现方式。

C#Attribute子类的实例

[AttributeUsage(AttributeTargets.Property, AllowMultiple = true, Inherited = true)]
public class MaxLengthAttribute: Attribute
{

	private int MaxLength {get;set;} = 10;
	public MaxLengthAttribute(int maxLength = 10){
		Console.WriteLine("MaxLengthAttribute");
		this.MaxLength = maxLength;
	}
	public bool checkMaxLength(string prop, string str){
		if (str == null){
			Console.WriteLine("Property {prop} is null");
			return false;
		}
		if (str.Length > MaxLength){
			Console.WriteLine($"Failed to update property {prop}. Its maximum length cannot exceed {this.MaxLength}.");
			return false;
		}
		return true;
	}
}
  • 限定该类只能修饰类中属性
  • 类中属性默认最大长度为10个字符,可以通过参数默认值实现定制。
  • checkMaxLength方法定义了检查方式,如果类中的属性长度大于指定值,报错。

Attribute子类的应用

using System;
using System.Reflection;	
using System.Linq;
public class Program
{
	public static void Main()
	{
		Engine engine = new Engine();
		engine.Vendor = "AVAVAAAA";
		engine.Type = "AVAVAAAAAVAVAAAAAVAVAAAAAVAVAAAAAVAVAAAA";
		var engineType = typeof(Engine);
		var properties = engineType.GetProperties();
		foreach (var property in properties){
			if (property.IsDefined(typeof(MaxLengthAttribute))){
				var maxlength = property.GetCustomAttributes<MaxLengthAttribute>().First();	
				maxlength.checkMaxLength(property.Name, (string)property.GetValue(engine));
			}
 
		}
	}
}
public class Engine {
	public Engine(){
		Console.WriteLine("Engine");
	}
	[MaxLength(5)]
	public string Vendor {get;set;}
	[MaxLength]
	public string Type {get;set;}
}
  • 自定义发动机类,该类有两个属性,供应商和型号。其*应商不能超过5个字符,型号不能超过10个。
  • 通过反射找到被MaxLength标识的Engine对象的供应商和型号属性,MaxLength起到了路标的作用。
  • 通过反射调用Attribute子类对象的checkMaxLength,检查属性字符串的长度。
  • 运行结果如下:
    C#的Attribute和Typescript的装饰器之比较
    从结果上可以看出如下:
  1. MaxLengthAttribute子类的实例化先于被装饰的内容Engine类的实例化。
  2. MaxLengthAttribute子类每次使用,编译器会实例化一个新的对象。

Typescript装饰器的实例

const maxLength = (max: number = 10) => (target: any, name: any) => {
  const key = "_temp" + new Date().getTime();
  Object.defineProperty(target, name, {
    get: function () {
      return this[key];
    },
    set: function (val) {
      if (val == null) {
        console.log(`Property ${name} is null.`);
        return;
      }
      if (val.length > max) {
        console.log(
          `Failed to update property ${name}. Its maximum length cannot exceed ${max}.`
        );
        return;
      }
      this[key] = val;
    },
  });
};
  • 因为要传递参数来限制最大允许的字符数,所以采用工厂方式定义该装饰器函数maxLength。
  • 采用defineProperty实现数据劫持,一旦赋值超过规定长度,则赋值失败。
  • 因为要支持多个属性的长度检查,所以通过new Date().getTime()来区分每个属性,以配合defineProperty的使用。

Typescript装饰器的使用


class Engine {
  @maxLength(5)
  public Vendor: string | undefined;
  @maxLength()
  public Type: string | undefined;
}

let p: Engine = new Engine();
p.Vendor = "1sssssssssssssssssssssssss";
p.Type = "2ssssssssssssssssssssssssssss";

通过tsc命令编译后,生成js代码并引入到html中,执行结果如下:
C#的Attribute和Typescript的装饰器之比较

结论

Attribute子类在.net的各种框架中已经大量使用,TypeScript的装饰器已经成为ES7的必备内容。虽然收到本身设计的限制,二者的实现方式并不同,但是却可以实现相同的功能,达到基于AOP编程的目标。

本文地址:https://blog.csdn.net/weixin_43263355/article/details/110137016