Unity游戏开发——C#特性Attribute与自动化

这篇文章主要讲一下C#里面Attribute的使用方法及其可能的应用场景。

比如你把玩家的血量、攻击、防御等属性写到枚举里面。然后界面可能有很多地方要根据这个枚举获取属性的描述文本。

比如你做网络框架的时候,一个协议号对应一个类的处理或者一个方法。

比如你做ORM,一个类的属性是否映射持久化文件中的属性,映射过去的属性名是什么。

 

1、什么是Attribute

如果用过Java的Annotation的同学,可以把Attribute当成Annotation来看待。

还不了解Attribute的同学不用急,我们看一下官方的解释:

The Attribute class associates predefined system information or user-defined custom information with a target element. A target element can be an assembly, class, constructor, delegate, enum, event, field, interface, method, portable executable file module, parameter, property, return value, struct, or another attribute.

Information provided by an attribute is also known as metadata. Metadata can be examined at run time by your application to control how your program processes data, or before run time by external tools to control how your application itself is processed or maintained. For example, the .NET Framework predefines and uses attribute types to control run-time behavior, and some programming languages use attribute types to represent language features not directly supported by the .NET Framework common type system.

All attribute types derive directly or indirectly from the Attribute class. Attributes can be applied to any target element; multiple attributes can be applied to the same target element; and attributes can be inherited by an element derived from a target element. Use the AttributeTargets class to specify the target element to which the attribute is applied.

The Attribute class provides convenient methods to retrieve and test custom attributes. For more information about using attributes, see Applying Attributes and Extending Metadata Using Attributes.

翻译过来就是:

    Attribute类可以把目标元素和一个预定义的信息或者是用户自定义信息关联起来。这里的目标元素可以是assembly,class,constructor,delegate,enum,event,field,interface,method,可执行文件模块,parameter,property,return value,struct或其它的Attribute。

    Attribute提供的信息也被称为元数据(metadata)。元数据能用于在运行时控制怎样访问你的程序数据,或者在运行前通过额外的工具来控制怎样处理你的程序或部署它。例如.NET Framework预定义并使用attribute去控制运行时行为,一些编程语言使用attribute类型来描述.NET Framework中通用类型不直接支持的语言特性。

    所有的Attribute类型直接或间接从Attribute类继承。Attribute能应用到任何target元素;多个Attribute能应用到相同的元素;

    Attribute类提供遍历的方法去取出和测试自定义Attribute。更多关于Attribute的信息,可以看Applying Attributes和Extending Metadata Using Attributes。

 

如果你看了官方的解释不明白,看了我的翻译也不明白。也没事。。。我们接下来举个例子看看Attribute能做啥。

2、用Attribute将枚举和一个描述文本绑定在一起

假设有这个枚举

[csharp] view plain copy

  1. public enum Properties  
  2. {  
  3.     /// <summary>  
  4.     /// 血量  
  5.     /// </summary>  
  6.     HP = 1,  
  7.   
  8.     /// <summary>  
  9.     /// 物理攻击  
  10.     /// </summary>  
  11.     PhyAtk = 2,  
  12.   
  13.     /// <summary>  
  14.     /// 物理防御  
  15.     /// </summary>  
  16.     PhyDef = 3,  
  17.   
  18.     /// <summary>  
  19.     /// 法术攻击  
  20.     /// </summary>  
  21.     MagAtk = 4,  
  22.   
  23.     /// <summary>  
  24.     /// 法术防御  
  25.     /// </summary>  
  26.     MagDef = 5  
  27. }  

注意:如果含中文的代码编译报“Newline in constant”的错。那么请将文件的编码保存为“带BOM的UTF-8”。VS中可以在“文件”-“高级保存选项”,然后选择编码下拉中选择。

 

然后你现在想要根据枚举来获得中文描述:比如传入:
Properties.MagDef返回“法术防御”。
最原始的做法:
[csharp] view plain copy

  1. public class PropertiesUtils  
  2. {  
  3.     public static string GetDescByProperties(Properties p)  
  4.     {  
  5.         switch (p)  
  6.         {  
  7.             case Properties.HP:  
  8.                 return "血量";  
  9.             case Properties.PhyAtk:  
  10.                 return "物理攻击";  
  11.             case Properties.PhyDef:  
  12.                 return "物理防御";  
  13.             case Properties.MagAtk:  
  14.                 return "法术攻击";  
  15.             case Properties.MagDef:  
  16.                 return "法术防御";  
  17.             default:  
  18.                 return "未知属性:" + p;  
  19.         }  
  20.     }  
  21. }  


这样确实可以解决问题,但是我们可以用Attribute来做的更好。可以做的更好干嘛不呢?
先定义一个用于存储描述文本的Attribute。[csharp] view plain copy

  1. [System.AttributeUsage(System.AttributeTargets.Field | System.AttributeTargets.Enum)]  
  2. public class PropertiesDesc : System.Attribute  
  3. {  
  4.     public string Desc { get; private set; }  
  5.   
  6. }  

没错,看起来是不是觉得很简单。
 

 

然后我们就可以把上面定义的PropertiesDesc加到Properties上面,像这样:

[csharp] view plain copy

  1. public enum Properties  
  2. {  
  3.   
  4.     [PropertiesDesc("血量")]  
  5.     HP = 1,  
  6.   
  7.     [PropertiesDesc("物理攻击")]  
  8.     PhyAtk = 2,  
  9.   
  10.     [PropertiesDesc("物理防御")]  
  11.     PhyDef = 3,  
  12.   
  13.     [PropertiesDesc("法术攻击")]  
  14.     MagAtk = 4,  
  15.   
  16.     [PropertiesDesc("法术防御")]  
  17.     MagDef = 5  
  18. }  

OK。这样,我们相当于就把一个文本描述信息通过Attribute关联到我们的枚举属性了。

那么怎样获取?我们来重写之前的PropertiesUtils类。

[csharp] view plain copy

  1. public class PropertiesUtils  
  2. {  
  3.     public static string GetDescByProperties(Properties p)  
  4.     {  
  5.         Type type = p.GetType();  
  6.         FieldInfo[] fields = type.GetFields();  
  7.         foreach (FieldInfo field in fields)  
  8.         {  
  9.             if (field.Name.Equals(p.ToString()))  
  10.             {  
  11.                 object[] objs = field.GetCustomAttributes(typeof(PropertiesDesc), true);  
  12.                 if (objs != null && objs.Length > 0)  
  13.                 {  
  14.                     return ((PropertiesDesc)objs[0]).Desc;  
  15.                 }  
  16.                 else  
  17.                 {  
  18.                     return p.ToString() + "没有附加PropertiesDesc信息";  
  19.                 }  
  20.             }  
  21.         }  
  22.         return "No Such field : "+p;  
  23.     }  
  24. }  

可以看到。这里面已经不用自己去判断哪个枚举值返回哪个字符串描述了。而是获取这个枚举域的PropertiesDesc对象。然后返回它的Desc属性。

当然,你还可以把上面的代码改成通用的,把Properties改成一个Type,这样就可以处理所有的枚举。然后还可以在查找PropertiesDesc的位置增加一个缓存。根据Type和字段的Name做缓存。改完后代码如下:

[csharp] view plain copy

  1. public class PropertiesUtils  
  2. {  
  3.     private  static Dictionary<Type, Dictionary<string, string>> cache = new Dictionary<Type, Dictionary<string, string>>();  
  4.   
  5.     public static string GetDescByProperties(object p)  
  6.     {  
  7.         var type = p.GetType();  
  8.         if (!cache.ContainsKey(type))  
  9.         {  
  10.             Cache(type);  
  11.         }  
  12.         var fieldNameToDesc = cache[type];  
  13.         var fieldName = p.ToString();  
  14.         return fieldNameToDesc.ContainsKey(fieldName) ? fieldNameToDesc[fieldName] : string.Format("Can not found such desc for field `{0}` in type `{1}`", fieldName, type.Name);  
  15.     }  
  16.   
  17.     private static void Cache(Type type)  
  18.     {  
  19.         var dict = new Dictionary<string, string>();  
  20.         cache.Add(type, dict);  
  21.         var fields = type.GetFields();  
  22.         foreach (var field in fields)  
  23.         {  
  24.             var objs = field.GetCustomAttributes(typeof(PropertiesDesc), true);  
  25.             if (objs.Length > 0)  
  26.             {  
  27.                 dict.Add(field.Name, ((PropertiesDesc)objs[0]).Desc);  
  28.             }  
  29.         }  
  30.     }  
  31. }  

3、还能干什么?

    Attribute能干的事情太多了,比如你写了个类,想做ORM映射,里面有些字段不想映射到表,有些想映射到表。有些字段可能名字和表的字段不一样。这时候你就可以通过Attribute来标识哪个字段需要被映射,映射到数据库哪个字段。等等。

    做过网络框架的同学也应该比较熟悉的一个应用,使用Attribute来做自动的消息派发。

    总之,Attribute可以做很多自动化的事情,就看你怎么用了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/246224.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Unity c#中Attribute用法详解

举两个例子&#xff0c;在变量上使用[SerializeFiled]属性&#xff0c;可以强制让变量进行序列化&#xff0c;可以在Unity的Editor上进行赋值。 在Class上使用[RequireComponent]属性&#xff0c;就会在Class的GameObject上自动追加所需的Component。 以下是Unity官网文档中找…

走进LWRP(Universal RP)的世界

走进LWRP&#xff08;Universal RP&#xff09;的世界 原文&#xff1a;https://connect.unity.com/p/zou-jin-lwrp-universal-rp-de-shi-jie LWRP自Unity2018发布以来&#xff0c;进入大家视野已经有一段时间了&#xff0c;不过对于广大Unity开发者来说&#xff0c;依然相对…

Unity 2017 Game Optimization 读书笔记(1)Scripting Strategies Part 1

1.Obtain Components using the fastest method Unity有多种Getcomponet的方法&#xff1a; GetComponent(string), GetComponent<T>() GetComponent(typeof(T)) 哪种效率最高会跟随Unity版本的变化而变化&#xff0c;对于Unity 2017&#xff0c;本书作者的测试是Ge…

C# 多态相关的文章

一 C# 多态的实现 封装、继承、多态&#xff0c;面向对象的三大特性&#xff0c;前两项理解相对容易&#xff0c;但要理解多态&#xff0c;特别是深入的了解&#xff0c;对于初学者而言可能就会有一定困难了。我一直认为学习OO的最好方法就是结合实践&#xff0c;封装、继承在…

C++ 虚函数和虚表

几篇写的不错的文章&#xff0c;本文是整合了这几篇文章&#xff0c;感谢这些大佬 https://www.jianshu.com/p/00dc0d939119 https://www.cnblogs.com/hushpa/p/5707475.html https://www.jianshu.com/p/91227e99dfd7 多态: 多态是面相对象语言一个重要的特性,多态即让同一…

Unity 2017 Game Optimization 读书笔记(2)Scripting Strategies Part 2

1. Share calculation output 和上一个Tip很像&#xff0c;可以缓存计算结果或者各种信息&#xff0c;避免多次重复的计算&#xff0c;例如在场景里查找一个物体&#xff0c;从文件读取数据&#xff0c;解析Json等等。 容易忽略的点是常常在基类了实现了某个方法&#xff0c;在…

Unity 2017 Game Optimization 读书笔记(3)Scripting Strategies Part 3

1.Avoid retrieving string properties from GameObjects 通常来讲&#xff0c;从C#的object中获取string 属性没有额外的内存开销&#xff0c;但是从Unity中的Gameobject获取string属性不一样&#xff0c;这会产生上一篇讲到的 Native-Managed Bridge&#xff08;Native内存和…

Unity 2017 Game Optimization 读书笔记(4)Scripting Strategies Part 4

1.Avoid Find() and SendMessage() at runtime SendMessage() 方法和 GameObject.Find() 相关的一系列方法都是开销非常大的。SendMessage()函数调用的耗时大约是一个普通函数调用的2000倍&#xff0c;GameObject.Find() 则和场景的复杂度相关&#xff0c;场景越复杂&#xff0…

Unity HDRP中的光照烘焙测试(Mixed Lighing )和间接光

部分内容摘抄自&#xff1a;https://www.cnblogs.com/murongxiaopifu/p/8553367.html 直接光和间接光 大家都知道在Unity中&#xff0c;我们可以在场景中布置方向光、点光、聚光等类型的光源。但如果只有这些光&#xff0c;则场景内只会受到直接光的影响&#xff0c;而所谓的…

聊聊Unity项目管理的那些事:Git-flow和Unity

感谢原作者https://www.cnblogs.com/murongxiaopifu/p/6086849.html 0x00 前言 目前所在的团队实行敏捷开发已经有了一段时间了。敏捷开发中重要的一个话题便是如何对项目进行恰当的版本管理。项目从最初使用svn到之后的Git One Track策略再到现在的GitFlow策略&#xff0c;中…

聊聊网络游戏同步那点事

写的非常好的一篇博文&#xff0c;转载自https://www.cnblogs.com/murongxiaopifu/p/6376234.html 0x00 前言 16年年底的时候我从当时的公司离职&#xff0c;来到了目前任职的一家更专注于游戏开发的公司。接手的是一个platform游戏项目&#xff0c;基本情况是之前的团队完成…

Unity 2017 Game Optimization 读书笔记 Dynamic Graphics(1)

The Rendering Pipeline 渲染表现差有可能取决于CPU端&#xff08;CPU Bound&#xff09;也有可能取决于GPU(GPU Bound).调查CPU-bound的问题相对简单&#xff0c;因为CPU端的工作就是从硬盘或者内存中加载数据并且调用图形APU指令。想找到GPU-bound的原因会困难很多&#xff…

Unity 2017 Game Optimization 读书笔记 Dynamic Graphics(2)

Lighting and Shadowing 现代的游戏中&#xff0c;基本没有物体能在一步就完成渲染&#xff0c;这是因为有光照和阴影的关系。光照和阴影的渲染在Fragment Shader中需要额外的pass。 首先要设置场景中的Shadow Casters和Shadow Receivers&#xff0c;Shadow Casters投射阴影&…

Unity 2017 Game Optimization 读书笔记 The Benefits of Batching

batching&#xff08;合批&#xff09; 和大量的描述一个3D物体的数据有关系&#xff0c;比如meshes&#xff0c;verices&#xff0c;edges&#xff0c;UV coordinates 以及其他不同类型的数据。在Unity中谈论batching&#xff0c;指的是用于合批mesh数据的两个东西&#xff1a…

Unity 2017 Game Optimization 读书笔记 Dynamic Graphics (3)

Rendering performance enhancements Enable/Disable GPU Skinning 开启GPU Skinning可以减轻CPU或GPU中Front End部分中某一个的负担&#xff0c;但是会加重另一个的负担。Skinning是mesh中的顶点根据动画中骨骼的当前位置进行计算&#xff0c;从而让角色摆出正确的姿势。 …

Unity手游开发札记——布料系统原理浅析和在Unity手游中的应用

原文&#xff1a;https://zhuanlan.zhihu.com/p/28644618 0. 前言 项目技术测试结束之后&#xff0c;各种美术效果提升的需求逐渐成为后续开发的重点&#xff0c;角色效果部分的提升目标之一便是在角色选择/展示界面为玩家提供更高的品质感&#xff0c;于是可以提供动态效果的…

行为树(Behavior Tree)实践(1)– 基本概念

原文&#xff1a;http://www.aisharing.com/archives/90 行为树&#xff08;Behavior Tree&#xff09;实践&#xff08;1&#xff09;– 基本概念 自从开博以来&#xff0c;每天都会关心一下博客的访问情况&#xff0c;看到一些朋友的订阅或者访问&#xff0c;不胜欣喜&…

Unity 2017 Game Optimization 读书笔记 Dynamic Graphics (5) Shader优化

Shader optimization Fill Rate和 Memory Bandwidth开销最大的地方就是Fragment Shader。开销多大取决于Fragment Shader的复杂程度&#xff1a;多少纹理需要采样&#xff0c;多少数学计算函数需要使用等等。GPU的并行特性意味着在线程中如果任何地方存在瓶颈&#xff0c;都会…

Unity 2017 Game Optimization 读书笔记 Dynamic Graphics (6)

1. Use less texture data 这条优化技巧非常直接&#xff0c;减少texture的数据量&#xff0c;减少分辨率或者降低位数&#xff0c;虽然可能会降低渲染质量。但是通常使用16-bit textures并不会明显的感觉到渲染效果下降。 MipMap技术可以有效减少VRAM和Texture Cache之间来回…

LeetCode 面试题57 - II(剑指offer) 和为s的连续正数序列

今天毕业五年了&#xff0c;一直忙于工作和享受&#xff0c;自从当年找完工作后就一直没有再刷过题&#xff0c;作为搬砖的码农&#xff0c;觉得还是应该养成长期刷题的习惯坚持下去。之前坚持了每天被一会单词&#xff0c;如今雅思一本也快看完了&#xff0c;从今天开始准备在…