C#和Unity中的特性

目录

1.System.Attribute 类

1.特性

2.原理

补充:

元数据是什么?

反射是什么?

2.预定义特性

AttributeUsage

Conditional

Obsolete

3.常用特性(持续更新)

4.实践自己定义一个特性

1.自定义一个绘制特性

2.用来为代码添加信息的特性


1.System.Attribute 类

1.特性

System.Attribute 类是所有自定义属性的基类,直接继承或者间接继承这个类的类型的叫做特性。

在unity开发中,说起特性想必大家都不算陌生,就比如[HideInInspector]等等(不着急哈,我后面会讲),C# 中的特性都是继承自 System.Attribute 类的,unity中的特性也同样如此。

它是用于在运行时传递程序中各种元素(比如类、方法、结构、枚举、组件等)的行为信息声明性标签,用于为代码添加元数据,如编译器指令和注释、描述、方法、类等其他信息。

2.原理

特性在编译时被处理,并生成元数据,在运行时,可以通过反射来读取这些元数据信息,从而实现各种自定义行为。

【注意:unity点击播放按钮时会先编译,转化为中间代码后再执行,因此上述说法并没啥问题】

补充:

元数据是什么?

C#程序集的数据:类型元数据,程序集元数据,IL代码,资源

  • 元数据:一般是指描述自身的数据的数据
  • 程序集元数据:包含了程序集的版本信息,安全信息,签名等
  • 类型元数据:记录程序集引用了哪些类,用户自定义了哪些类,字段,数据等一系列的信息
  • IL代码(中间代码):C#编译成IL代码,保存到程序集中,通过CLR(公共语言运行时)加载后由JIT(即时编译器)调用基础类库编译成机器码在CPU上运行
  • 资源:图片,音频,视频等
反射是什么?

反射指程序可以访问、检测和修改它本身状态或行为的一种能力。

程序集包含模块,而模块包含类型,类型又包含成员。反射则提供了封装程序集、模块和类型的对象。

您可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型。然后,可以调用类型的方法或访问其字段和属性。

优点:

  • 1、反射提高了程序的灵活性和扩展性。
  • 2、降低耦合性,提高自适应能力。
  • 3、它允许程序创建和控制任何类的对象,无需提前硬编码目标类。

缺点:

  • 1、性能问题:使用反射基本上是一种解释操作,用于字段和方法接入时要远慢于直接代码。因此反射机制主要应用在对灵活性和拓展性要求很高的系统框架上,普通程序不建议使用。
  • 2、使用反射会模糊程序内部逻辑;程序员希望在源代码中看到程序的逻辑,反射却绕过了源代码的技术,因而会带来维护的问题,反射代码比相应的直接代码更复杂。

反射有下列用途:

  • 它允许在运行时查看特性(attribute)信息。
  • 它允许审查集合中的各种类型,以及实例化这些类型。
  • 它允许延迟绑定的方法和属性(property)。
  • 它允许在运行时创建新类型,然后使用这些类型执行一些任务。

2.预定义特性

是.net提供的、预先定义好的特性,它们用于标记和描述程序中的各种元素。

.net提供了三个预定义特性:

AttributeUsage

[AttributeUsage(validon,AllowMultiple=allowmultiple,Inherited=inherited)]

该特性只能作用于继承了Attribute类的类。
用于约束和规定自定义特性


第一个参数:指定应用目标
/*
第一个参数 validOn 指定了自定义特性可以应用到哪些程序元素。
这个参数的类型是 AttributeTargets 枚举,可以是以下值之一:All、Class、Struct
、Enum、Constructor、Method、Property、Field、Event、Interface、Delegate 等。
你可以选择一个或多个值,使用 | 运算符来组合它们。
*/
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class MyAttribute : Attribute
{
    // ...
}

第二个参数:是否允许多重应用
/*
默认值为 false,即不允许多重应用。
AllowMultiple 参数指定了是否可以在同一程序元素上应用多个实例。
*/

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class MyAttribute : Attribute
{
    // ...
}

[MyAttribute]
[MyAttribute] // 编译错误:特性 'MyAttribute' 只能应用一次。
public class MyClass
{
    // ...
}

第三个参数:是否被子类继承
/*
Inherited 参数指定了特性是否被子类继承
默认值为 false,即不允许被子类继承。
*/

[AttributeUsage(AttributeTargets.Class, Inherited = false)]
public class MyAttribute : Attribute
{
    // ...
}

[MyAttribute]
public class BaseClass
{
    // ...
}

public class DerivedClass : BaseClass
{
    // MyAttribute 不会自动应用到这里,除非显式添加
}


Conditional

[Conditional(conditionalSymbol)]

该特性针对一个特性类或者方法。
通常用于调试和日志记录,但也可以用于其他需要条件编译的场景。


conditionalSymbol参数:指定一个字符串参数,这个字符串参数是编译器需要定义的符号

public class MyClass
{
    [Conditional("DEBUG")]
    public void DebugMethod()
    {