特性Attribute知识补充

2018-07-16  本文已影响0人  地坛公园

前言:昨天着急看世界杯,急急忙忙发了Attribute的那篇文章,今天回看书籍的时候,发现遗漏了一点知识,在这里再补充上来

一、关于两个特性实例的相互匹配
除了判断是否向某一个目标元素上是否应用了某一特性之外,可能还需要与匹配两个特性是否是同一个特性,System.Attribute重写了Object的Equals方法,会在内部比较两个对象的类型。会利用反射来获取特性中的字段,并为每个字段均调用Equals方法,所有的字段均匹配才返回true,我们可以重写Equals方法来移除反射的使用,从而提高程序的性能。

System.Attribute还重写了虚方法Match,Match默认只是调用Equals方法并返回结果,所以这两个方法都可以进行重写,来移除反射的使用。

using System;
using UnityEngine;


[Flags]
internal enum Accounts{
    Savings=0x0001,
    Checking=0x0002,
    Brokerage=0x0004
}

[AttributeUsage(AttributeTargets.Class)]
internal sealed class AccountsAttribute:System.Attribute
{
    private Accounts m_accouunts;
    public AccountsAttribute(Accounts accounts)
    {
        m_accouunts = accounts;
    }

    public override Boolean Match(object obj)
    {
        if (obj == null) {
            return false;
        }

        if (this.GetType () != obj.GetType ()) {
            return false;
        }


        AccountsAttribute o = (AccountsAttribute)obj;
        if ((o.m_accouunts & m_accouunts) != m_accouunts) {
            return false;
        }
        return true;
    }

    public override Boolean Equals(object obj)
    {
        if (obj == null) {
            return false;
        }

        if (this.GetType () != obj.GetType ()) {
            return false;
        }

        AccountsAttribute o = (AccountsAttribute)obj;
        if (o.m_accouunts!=m_accouunts) {
            return false;
        }

        return true;
    }

    public override Int32 GetHashCode()
    {
        return (Int32)m_accouunts;
    }
}

[Accounts(Accounts.Savings)]
internal sealed class ChildAccount{}

[Accounts(Accounts.Savings|Accounts.Checking|Accounts.Brokerage)]
internal sealed class AdultAccount{}

public sealed class Program
{

    public void Test()
    {
        CanWriteCheck (new ChildAccount ());
        CanWriteCheck (new AdultAccount ());


        CanWriteCheck (new Program ());

    }

    private static void CanWriteCheck(object obj)
    {
        Attribute checking = new AccountsAttribute (Accounts.Checking);

        Attribute validAccounts = Attribute.GetCustomAttribute (obj.GetType (), typeof(AccountsAttribute), false);

        if (validAccounts != null && checking.Match (validAccounts)) {
            Debug.Log (obj.GetType () + " types can write checks.");
        } else {
            Debug.Log (obj.GetType () + " types can NOT write checks.");
        }
    }
}

说明:
重写Match,Equals方法,Match判断两者是否匹配,而Equals则是判断两个对象是否相等,如果override了Equals,就
必须要重写GetHashCode(),刚才这里迟疑了一下,不明为何要一定重写GetHashCode(),查了查资料,豁然开朗,稍后会
新起一章单独讲讲这一块。

Equals时,是比较两个在拖管堆内存中独立的两个对象,首先要确保参数对象不是null,然后要确保他们在
元数据中的Type引用是同一个,再去比较具体的字段或属性是否满足相等的条件!

通过上面的代码就可以方便的去匹配两个特性。

二、特性条件类

在设计和调试的过程中,通过特性可以辅助开发,带来更多的便利性。
比如在U3D中开发一款消除游戏,我们设置了一个ID来保存关卡信息,不管他是一个对象还是值类型,我们在调试过程中有时候会经常切换这个值来测试不同的关卡,
这时候就可以通过特性Attribute,在ID上应用特性,并在Inspector面板中显示出当前有哪可用的关卡,以及具体的关卡信息,更方便,更直观的查看。
或是音乐文件比较多的游戏中,可以通过特性实现不同音乐的分类等等,但这些信息仅用于调试阶段,在正式
发布运行中,并不会用到,所以将这些特性的数据保存到元数据,无疑会增加元数据的大小,从而增加程序集的大小,
也会影响反射的效率,那么通过条件特性类就可以解决这个问题,只是在测试环境中使用,在正式环境中,在目标元素上应用的这些调试性的特性就不会写入到元数据中。从而减少数据冗余。

如:

#define DEBUG
#define VERITY

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Reflection;
using System;
using System.Diagnostics;
using  System.Runtime.InteropServices;



[AttributeUsage(AttributeTargets.Class)][Conditional("DEBUG")][Conditional("VERIFY")]
public class TestCondAttribute:System.Attribute
{
    public TestCondAttribute()
    {
    }

}

[TestCond]
public class main3 : MonoBehaviour {

    // Use this for initialization
    void Start () {
        
    }
    
    // Update is called once per frame
    void Update () {
        
    }
}

编译如果发现了向目标元素应用了TestCondAttribute特性,那么当含有目标元素的代码编译时,只有定义了DEBUG或是
VERIFY符号的前提下,编译才会在元数据中生成特性信息,但TestCondAttribute特性类的定义仍存在于程序集中。


到此为止,如果大家发现有什么不对的地方,欢迎指正,共同提高,感谢您的阅读!

编辑于2018.7.16

可喜的,Luka Modric 虽然输掉了世界杯(意料之中,法国体能,实力,运气都占上风,天选),但还是如愿以偿的拿到了世界杯金球场,在世界杯决赛开始之前,以63公里的跑动排在第一位,世界杯上可以看到,他已经有些力体不支了,实至名归。
魔笛加油,世界级中场大师!!!

822059393243086478.jpg
上一篇 下一篇

猜你喜欢

热点阅读