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

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

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

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

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

1、什么是Attribute

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

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

Attribute 类将预定义的系统信息或用户定义的自定义信息与目标元素相关联。" xml:space="preserve" style="background-color: rgb(255, 255, 225);">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.

Attribute 类派生。" xml:space="preserve">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. AttributeTargets 类可以指定特性所应用到的目标元素。" xml:space="preserve">Use the AttributeTargets class to specify the target element to which the attribute is applied.

Attribute 类提供检索和测试自定义特性的简便方法。" xml:space="preserve">The Attribute class provides convenient methods to retrieve and test custom attributes. 应用特性和利用特性扩展元数据。" xml:space="preserve">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 AttributesExtending Metadata Using Attributes

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

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

假设有这个枚举

public enum Properties
{
    /// <summary>
    /// 血量
    /// </summary>
    HP = 1,

    /// <summary>
    /// 物理攻击
    /// </summary>
    PhyAtk = 2,

    /// <summary>
    /// 物理防御
    /// </summary>
    PhyDef = 3,

    /// <summary>
    /// 法术攻击
    /// </summary>
    MagAtk = 4,

    /// <summary>
    /// 法术防御
    /// </summary>
    MagDef = 5
}

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

然后你现在想要根据枚举来获得中文描述:比如传入:

Properties.MagDef返回“法术防御”。
最原始的做法:
public class PropertiesUtils
{
    public static string GetDescByProperties(Properties p)
    {
        switch (p)
        {
            case Properties.HP:
                return "血量";
            case Properties.PhyAtk:
                return "物理攻击";
            case Properties.PhyDef:
                return "物理防御";
            case Properties.MagAtk:
                return "法术攻击";
            case Properties.MagDef:
                return "法术防御";
            default:
                return "未知属性:" + p;
        }
    }
}

这样确实可以解决问题,但是我们可以用Attribute来做的更好。可以做的更好干嘛不呢?

先定义一个用于存储描述文本的Attribute。
[System.AttributeUsage(System.AttributeTargets.Field | System.AttributeTargets.Enum)]
public class PropertiesDesc : System.Attribute
{
    public string Desc { get; private set; }

}

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

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

public enum Properties
{

    [PropertiesDesc("血量")]
    HP = 1,

    [PropertiesDesc("物理攻击")]
    PhyAtk = 2,

    [PropertiesDesc("物理防御")]
    PhyDef = 3,

    [PropertiesDesc("法术攻击")]
    MagAtk = 4,

    [PropertiesDesc("法术防御")]
    MagDef = 5
}

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

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

public class PropertiesUtils
{
    public static string GetDescByProperties(Properties p)
    {
        Type type = p.GetType();
        FieldInfo[] fields = type.GetFields();
        foreach (FieldInfo field in fields)
        {
            if (field.Name.Equals(p.ToString()))
            {
                object[] objs = field.GetCustomAttributes(typeof(PropertiesDesc), true);
                if (objs != null && objs.Length > 0)
                {
                    return ((PropertiesDesc)objs[0]).Desc;
                }
                else
                {
                    return p.ToString() + "没有附加PropertiesDesc信息";
                }
            }
        }
        return "No Such field : "+p;
    }
}

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

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

public class PropertiesUtils
{
    private  static Dictionary<Type, Dictionary<string, string>> cache = new Dictionary<Type, Dictionary<string, string>>();

    public static string GetDescByProperties(object p)
    {
        var type = p.GetType();
        if (!cache.ContainsKey(type))
        {
            Cache(type);
        }
        var fieldNameToDesc = cache[type];
        var fieldName = p.ToString();
        return fieldNameToDesc.ContainsKey(fieldName) ? fieldNameToDesc[fieldName] : string.Format("Can not found such desc for field `{0}` in type `{1}`", fieldName, type.Name);
    }

    private static void Cache(Type type)
    {
        var dict = new Dictionary<string, string>();
        cache.Add(type, dict);
        var fields = type.GetFields();
        foreach (var field in fields)
        {
            var objs = field.GetCustomAttributes(typeof(PropertiesDesc), true);
            if (objs.Length > 0)
            {
                dict.Add(field.Name, ((PropertiesDesc)objs[0]).Desc);
            }
        }
    }
}

3、还能干什么?

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

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

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

时间: 2024-08-30 12:44:00

Unity游戏开发——C#特性Attribute与自动化的相关文章

【Unity游戏开发】不接SDK也能在游戏内拉起加QQ群操作?

一.引子 一般在游戏进行对外测试的时候都会有一个玩家QQ群,方便玩家反馈问题.交流游戏心得等.那么为了增加玩家加QQ群的欲望,可能会在游戏里面设计一个小功能,点击一下可以直接拉起手Q加群的操作,加了QQ群以后,也会自动下发一些小奖励刺激玩家.原本我以为要拉起手Q加QQ群的操作一定要接入相关平台的SDK才行,直到我详细地阅读了下腾讯官网的QQ群官方主页,我才了解到在游戏内拉起手Q发起加群的操作是如此的简单,根本不需要接入任何第三方SDK,只需短短几行代码即可轻松实现.闲言少叙,书归正文,咱们马上就

C# Unity游戏开发——Excel中的数据是如何到游戏中的 (二)

本帖是延续的:C# Unity游戏开发——Excel中的数据是如何到游戏中的 (一) 上个帖子主要是讲了如何读取Excel,本帖主要是讲述读取的Excel数据是如何序列化成二进制的,考虑到现在在手游中应用很广泛的序列化技术Google的ProtoBuf,所以本文也是按照ProtoBuf的方式来操作的.ProtoBuf是一个开源库,简单来说ProtoBuf就是一个能使序列化的数据变得更小的类库,当然这里指的更小是相对的.好了ProtBuf的东西就不在多说,以后会专门写一篇帖子的.本帖其实就相当于上

C# Unity游戏开发——Excel中的数据是如何到游戏中的 (三)

本帖是延续的:C# Unity游戏开发——Excel中的数据是如何到游戏中的 (二) 前几天有点事情所以没有继续更新,今天我们接着说.上个帖子中我们看到已经把Excel数据生成了.bin的文件,不过其实这样到游戏中还是不能用的.主要有两个方面,1.bin文件的后缀使我们随便取的名字,但是这种文件Unity不买账.因为Unity中的二进制文件必须是以.bytes命名的.2.在写文件之前其实还可以对二进制进行压缩,这样可以最大化节省设备空间.也就是说我们在生成数据实例后还需要做以下几件事:序列化 -

Unity 游戏开发技巧集锦之使用cookie类型的纹理模拟云层的移动

Unity 游戏开发技巧集锦之使用cookie类型的纹理模拟云层的移动 使用cookie类型的纹理模拟云层的移动 现实生活中,当阳光直射大地,而天空中又有很多云时,云层的影子总是会投射在大地上,风吹着云层移动,影子也跟着运动,如图3-28所示. 图3-28  天空中的云朵与大地上的影子 要在游戏中,模拟与之类似的大气现象时,就需要使用cookie类型的纹理. 制作云层效果的纹理 本小节将使用PhotoShop绘制有云层效果的纹理图,然后为其添加透明度信息.具体操作过程如下: (1)使用Photo

Unity 游戏开发技巧集锦之创建透明的材质

Unity 游戏开发技巧集锦之创建透明的材质 Unity创建透明的材质 生活中不乏透明或者半透明的事物.例如,擦的十分干净的玻璃,看起来就是透明的:一些塑料卡片,看起来就是半透明的,如图3-23所示.在Unity中,可以创建模拟了透明效果的材质,这也是本节主要讲解的内容. 图3-23  半透明的卡片 Unity创建并配置材质 在Project视图里,创建一个材质,并命名为TransMaterial,选中它然后在Inspector视图里修改Shader属性为Transparent/Diffuse,

?Unity 游戏开发技巧集锦之使用忍者飞镖创建粒子效果

Unity 游戏开发技巧集锦之使用忍者飞镖创建粒子效果 使用忍者飞镖创建粒子效果 游戏中,诸如烟.火.水滴.落叶等粒子效果,都可以使用粒子系统(particle system)来实现.例如,<明朝传奇>中的篝火,如图2-32所示.粒子系统的最新版本也被称做忍者飞镖(Shuriken),因为场景中添加的粒子系统酷似忍者飞镖,如图2-33所示. 图2-32  游戏中的篝火               图2-33  粒子系统,也被称为忍者飞镖 unity中粒子基本属性 在使用粒子系统前,先了解一下它

unity游戏开发之自定义事件测试demo

上文中写了unity游戏开发自定义消息事件点击打开链接 下面是测试demo 第一,打卡unity,新建一个场景,然后新建一个空的游戏对象,如图中的EventObj 第二步,测试代码EventTest.as,直接拖拽给上面的空游戏对象EentObj 测试代码如下: using UnityEngine; using System.Collections; public class EventTest : MonoBehaviour { // Use this for initialization v

Unity 游戏开发技巧集锦之制作一个望远镜与查看器摄像机

Unity 游戏开发技巧集锦之制作一个望远镜与查看器摄像机 Unity中制作一个望远镜 本节制作的望远镜,在鼠标左键按下时,看到的视图会变大:当不再按下的时候,会慢慢缩小成原来的视图.游戏中时常出现的狙击手就是使用望远镜的一个例子,如图2-22所示.   图2-22  游戏中狙击手所看到的视图 制作望远镜的过程如下: (1)在Project视图里,创建一个C#脚本文件,命名为TelescopicView.打开这个脚本文件,并在里面添加下面的代码: 01     using UnityEngine

Unity游戏开发实战视频教程

Unity客户端架构设计与网络游戏关键技术(Avatar,热更新,Protobuf)课程分类:游戏开发适合人群:中级课时数量:20(42节)课时用到技术:Unity客户端,UI设计框架,Avatar换装,Protobuf-net等涉及项目:搭建Unity客户端 UI设计框架以及Avatar换装和移动端热更新技术实现以及Protobuf-net在Unity中运用咨询qq:1840215592 课程介绍:1.课程研发环境开发工具:Unity4.6和VS20082.内容简介本课程内容详细介绍了如何实现