はなちるのマイノート

Unityをメインとした技術ブログ。自分らしくまったりやっていきたいと思いますー!

【Unity】TypeCacheを用いて"特定の属性でマークされている型やメソッド" や "特定のクラスやインターフェイスから派生する型"に素早くアクセスする

はじめに

今回はTypeCacheを用いて"特定の属性でマークされた型の一覧"や”特定のクラスやインターフェースから派生する型"をリフレクションよりも高速に取得する方法について紹介したいと思います。

docs.unity3d.com

概要

TypeCacheを用いることで特定の属性でマークされている型やメソッド、特定のクラスやインターフェイスから派生する型に素早くアクセスすることができるようになります。ただエディタ専用でランタイムでは動作しません。Unity2019.2から登場したようです。
Unity 2019.2:プログラマー向けの新しいツールと機能 | Unity

Provides methods for fast type extraction from asssemblies loaded into the Unity Domain.

Use TypeCache to access attributes and derived types information. This cache allows arbitrary Editor code to leverage from native cache data.

It is a common use case to extract types marked with a specific attribute, or for classes that extend or implement a specific type, when building or extending the Unity Editor. Iterating types in the current domain is usually a slow operation that scales linearly based on the number of types.

To speed up type extraction, the Editor builds an acceleration table, on the native side, that contains information about type attributes and derived classes.

// DeepL翻訳
Unity Domainにロードされたアセンブリから高速に型を抽出するメソッドを提供します。

TypeCache を使用して、属性と派生型の情報にアクセスします。このキャッシュにより、任意のエディタコードがネイティブキャッシュデータを活用できるようになります。

Unityエディタを構築または拡張するときに、特定の属性でマークされた型、または特定の型を拡張または実装するクラスを抽出するのは一般的な使用例です。現在のドメインで型を反復処理することは、通常、型の数に基づいて線形にスケールする遅い操作です。

型の抽出を高速化するために、エディタはネイティブ側で、型の属性と派生クラスに関する情報を含むアクセラレーションテーブルを構築します。

TypeCache - Unity スクリプトリファレンス

リフレクションでも同様の操作をすることができますが、TypeCacheを用いると高速で動作するのでランタイムでなければ積極的に利用していきましょう。

TypeCacheには以下の4つのメソッドが用意されています。

  • TypeCache.GetFieldsWithAttribute
  • GetMethodsWithAttribute
  • GetTypesDerivedFrom
  • GetTypesWithAttribute

使い方

TypeCache.GetFieldsWithAttribute

TypeCache.GetFieldsWithAttribute特定の属性でマークされているフィールドの一覧を取得します。

Retrieves an unordered collection of fields marked with the T attribute.

// DeepL翻訳
T属性でマークされたフィールドの順序なしコレクションを取得します。

// TypeCache.GetFieldsWithAttribute
public static TypeCache.FieldInfoCollection GetFieldsWithAttribute ();
public static TypeCache.FieldInfoCollection GetFieldsWithAttribute (Type attrType);
public static TypeCache.FieldInfoCollection GetFieldsWithAttribute (string assemblyName);
public static TypeCache.FieldInfoCollection GetFieldsWithAttribute (Type attrType, string assemblyName);

TypeCache-GetFieldsWithAttribute - Unity スクリプトリファレンス

// サンプルコード
public class Sample
{
    [Sample] private int _hoge;

    [Sample] private bool _fuga;
    
    [MenuItem("Sample/Execute")]
    public static void Execute()
    {
        TypeCache.FieldInfoCollection fields = TypeCache.GetFieldsWithAttribute<SampleAttribute>();

        foreach (FieldInfo fieldInfo in fields)
        {
            // _hoge, _fuga
            Debug.Log(fieldInfo.Name);   
        }
    }

    public class SampleAttribute : Attribute  
    {
        public SampleAttribute() { }  
    } 
}

TypeCache.GetMethodsWithAttribute

TypeCache.GetMethodsWithAttributeを用いると特定の属性でマークしたメソッドの一覧を取得できます。

Retrieves an unordered collection of methods marked with the T attribute.

// DeepL翻訳
T 属性でマークされたメソッドの順序なしコレクションを取得します。

// TypeCache.GetMethodsWithAttribute
public static TypeCache.MethodCollection GetMethodsWithAttribute ();
public static TypeCache.MethodCollection GetMethodsWithAttribute (Type attrType);
public static TypeCache.MethodCollection GetMethodsWithAttribute (string assemblyName);
public static TypeCache.MethodCollection GetMethodsWithAttribute (Type attrType, string assemblyName);

TypeCache-GetMethodsWithAttribute - Unity スクリプトリファレンス

// サンプルコード
public class Sample
{
    [MenuItem("Sample/Execute")]
    public static void Execute()
    {
        TypeCache.MethodCollection methods = TypeCache.GetMethodsWithAttribute<SampleAttribute>();

        foreach (MethodInfo methodInfo in methods)
        {
            // Hoge, Fuga
            Debug.Log(methodInfo.Name);   
        }
    }

    [Sample]
    private void Hoge() { }

    [Sample]
    private void Fuga() { }
    
    public class SampleAttribute : Attribute  
    {
        public SampleAttribute() { }  
    } 
}

TypeCache.GetTypesDerivedFrom

TypeCache.GetTypesDerivedFrom特定のクラス・インターフェースから派生する型の一覧を取得します。

Retrieves an unordered collection of types derived from the T type.

// DeepL翻訳
T型から派生した型の順序なしコレクションを取得します。

// TypeCache.GetTypesDerivedFrom
public static TypeCache.TypeCollection GetTypesDerivedFrom ();
public static TypeCache.TypeCollection GetTypesDerivedFrom (Type parentType);
public static TypeCache.TypeCollection GetTypesDerivedFrom (string assemblyName);
public static TypeCache.TypeCollection GetTypesDerivedFrom (Type parentType, string assemblyName);

TypeCache-GetTypesDerivedFrom - Unity スクリプトリファレンス

// サンプルコード1
public class Sample
{
    public interface ISample { }
    
    public class Hoge : ISample { }
    public class Fuga : ISample { }

    [MenuItem("Sample/Execute")]
    public static void Execute()
    {
        TypeCache.TypeCollection types = TypeCache.GetTypesDerivedFrom<ISample>();

        foreach (Type type in types)
        {
            // Sample+Hoge, Sample+Fuga
            Debug.Log(type);   
        }
    }
}
// サンプルコード2
public class Sample
{
    public class SampleComponentBase { }
    public class SampleComponentA : SampleComponentBase{}
    public class SampleComponentB : SampleComponentBase{}

    [MenuItem("Sample/Execute")]
    public static void Execute()
    {
        TypeCache.TypeCollection components = TypeCache.GetTypesDerivedFrom<SampleComponentBase>();

        foreach (Type component in components)
        {
            // Sample+SampleComponentA,Sample+SampleComponen
            Debug.Log(component);   
        }
    }
}

TypeCache.GetTypesWithAttribute

TypeCache.GetTypsWithAttributeを用いると特定の属性でマークした型の一覧を取得できます。

Retrieves an unordered collection of types marked with the T attribute.

This method provides fast access to all classes loaded from a given assembly or all Unity domain assemblies and marked with a specific attribute. Types marked with ancestors of the specified attribute are also included in the result. The order of results is undefined.

T属性でマークされた型の順序なしコレクションを取得します。

このメソッドは、指定されたアセンブリまたはすべての Unity ドメイン・アセンブリからロードされ、特定の属性でマーク付けされたすべてのクラスへの高速アクセスを提供します。指定された属性の祖先でマーク付けされた型も結果に含まれます。結果の順序は未定義です。

// TypeCache.GetTypesWithAttribute
public static TypeCache.TypeCollection GetTypesWithAttribute ();
public static TypeCache.TypeCollection GetTypesWithAttribute (Type attrType);
public static TypeCache.TypeCollection GetTypesWithAttribute (string assemblyName);
public static TypeCache.TypeCollection GetTypesWithAttribute (Type attrType, string assemblyName);

TypeCache-GetTypesWithAttribute - Unity スクリプトリファレンス

// サンプルコード
public class Sample
{
    public class SampleComponentBase { }
    [Sample] public class SampleComponentA : SampleComponentBase{}
    [Sample] public class SampleComponentB : SampleComponentBase{}

    [MenuItem("Sample/Execute")]
    public static void Execute()
    {
        TypeCache.TypeCollection components = TypeCache.GetTypesWithAttribute<SampleAttribute>();

        foreach (Type component in components)
        {
            // Sample+SampleComponentA,Sample+SampleComponen
            Debug.Log(component);   
        }
    }
    
    public class SampleAttribute : Attribute  
    {
        public SampleAttribute() { }  
    } 
}