Unclaimed Package Is this your package? Claim it to unlock full analytics and manage your listing.
Claim This Package

Install via UPM

Add to Unity Package Manager using this URL

https://www.pkglnk.dev/track/directattribute.git

README

DirectRetrieveAttribute

GitHub last commit GitHub package.json version openupm

为什么有用

使用额外的全局数据而不是反射遍历来实现Attribute查找和子类查找。(允许自动preserve目标)

可以满足以下三大常见需求:

  • 高效获取Attribute
  • 高效获取子类(提供basetype)和实现类(提供interface)
  • 通过Attribute实例直接获取标记的类或成员

快速开始

安装

via Git URL

Package Manager通过git url安装: https://github.com/labbbirder/DirectRetrieveAttribute.git

via OpenUPM

openupm add com.bbbirder.directattribute

检索Attribute

using BBBirder.DirectAttribute;

//自定义Attribute继承DirectRetrieveAttribute
class FooAttribute : DirectRetrieveAttribute 
{
    // 自动Preserve标记的成员,防止strip
    public override bool PreserveTarget => true;

    public string title { get; private set; }
    
    public FooAttribute(string title)
    {
        this.title = title;
        // dont access TargetMember here, it will always be null
    }
    
    public override void OnReceiveTarget()
    {
        // TargetMember is available here ^_^
        Debug.Log(TargetMember);
    }
}

//作出标记
[Foo("whoami")]
class Player
{
    [Foo("Hello")]
    void Salute()
    {

    }
}

//检索当前Domain下所有FooAttribute
FooAttribute[] attributes = Retriever.GetAllAttributes<FooAttribute>(); 
foreach(var attr in attributes)
{
    print($"{attr.TargetMember.Name} {attr.title}"); 
}
// output: 
//    Player whoami
//    Salute Hello

自定义Attribute需要继承DirectRetrieveAttributeRetriever.GetAllAttributes会在检索过程中赋值目标成员TargetMember并调用OnReceiveTarget()通知赋值完成。

检索子类型

using BBBirder.DirectAttribute;

// 定义几个类型
public class Battler:IDirectRetrieve
{

}

public class Hero:Battler
{

}

public class Titant:Hero
{

}

// 获取Domain下所有Battler子类
Type[] types = Retriever.GetAllSubtypes<Battler>();
foreach(var type in types)
{
    print($"{type.Name}");
}
// output:
//     Hero
//     Titant

接口的实现检索与上例类似。

传统方式对比

传统方式获取Attributes列表

在传统方式下,我们可能会这样获取所有自定义属性:

AppDomain.CurrentDomain.GetAssemblies()
    .SelectMany(a=>a.GetTypes())
    .SelectMany(a=>a.GetMembers()
        .SelectMany(m=>m.GetCustomAttributes(attrType)))
    .ToArray();

众所周知,反射方法效率低,并且会产生大量GC。如果你是一个Package Developer,在你开发的众多Package中可能有不少需要检索Attribute列表的情况,这无疑是灾难性的。

实现原理

开发者编辑代码时使用源生成方式写入额外信息,并提供RoslynAnalyzer保证代码准确性。

现在,只有真正编译发生时,才分析语法,并生成这些信息。

使用反编译工具打开Unity自动生成的Dll,可以看到类似下面的额外元数据:


namespace BBBirder
{
    internal static class RetrieveModule
    {
        static Dictionary<Type, HashSet<Type>> subTypes;

        static Dictionary<Type, HashSet<MemberInfo>> targetMembers;

        static Type s_attrType;

        static RetrieveModule()
        {
            s_attrType = Type.GetType("BBBirder.DirectAttribute.DirectRetrieveAttribute, BBBirder.DirectAttribute");

            // 涉及到的上层模块类型,需要通过AQN获取
            var @type0 = Type.GetType("MyType1, MyModule");

            // 当前模块的Attribute字典
            targetMembers = new()
            {
                [typeof(MyAttribute)] = new HashSet<MemberInfo>()
                    .Collect(typeof(MyType2), "MyMethod2")
                    .Collect(@type0, "MyMethod")
                    ,
            };

            // 当前模块的类型继承树
            subTypes = new()
            {
                [@type0] = new () {
                    typeof(MyType2),
                    typeof(MyType3),
                    typeof(MyType4),
                },
            };
        }

    }
}

为什么不实现写入MetadataToken到Assembly Resource?

考虑到有的项目可能需要DLL织入,MetadataToken会发生变化。

Total Installs
0
Last 30 days
Unique IPs
0
Approximate users

Installs Over Time

Operating Systems

No data yet

Top Countries

No data yet

Git Versions

No data yet

Embed Install Badge

Add an install count badge to your README

Style
Preview
pkglnk installs badge
Markdown
[![pkglnk installs](https://www.pkglnk.dev/badge/directattribute.svg?style=pkglnk)](https://www.pkglnk.dev/pkg/directattribute)
HTML
<a href="https://www.pkglnk.dev/pkg/directattribute"><img src="https://www.pkglnk.dev/badge/directattribute.svg?style=pkglnk" alt="pkglnk installs"></a>

Comments

No comments yet. Be the first!