はなちるのマイノート

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

【Unity】コンパイル後のdllに対してリフレクションを利用せずにasmrefを使ってinternalにアクセスする方法(必ずできるわけではない)

はじめに

今回はコンパイル後のdllに対してリフレクションを利用せずにasmrefを使ってinternalにアクセスする方法について紹介したいと思います。

この記事を見ている方ならasmrefについての説明は大丈夫かと思いますが、一応前書いておいた記事を貼っておきます。
www.hanachiru-blog.com

とても便利なasmrefですが、コンパイル前でなければアセンブリにコードを埋め込むことはできません。(つまりasmdefが定義されてないとダメ)

ですのでコンパイル済のdllに対してはasmrefを使って直接internalの利用することができないのです。しかしちょっと邪道?なやり方でそれを擬似的に実現できる場合があります。

概要

コンパイル済であったとしても、アセンブリの中にInternalsVisibleToが記載されていれば希望があります。

InternalVisibleToを利用している様子

www.hanachiru-blog.com


やり方としてはInternalsVisibleToに含まれているアセンブリにasmdefが定義されていたら、そこにasmrefを用いてコードをアセンブリに組み込むことで、間接的に対象アセンブリのinternalにアクセスします。

以下実験で用いたアセンブリの関係性を載せておきます。

アセンブリの関係性

例えば上記サンプルのTargetSample.dllHoge.asmdefのどちらもUnityが提供しているパッケージであったと考えます。ユーザーが書いたSample.csTargetSample.dllinternalにアクセスしようとしたらまずリフレクションが候補にあがります。

しかしよくコードをみるとTargetSample.dllにはInternalVisibleToが定義されており、Hoge.asmdefからはinternalにアクセスできることに気がつきました。

というわけでasmrefを利用してHoge.asmdefにコードを組み込めば、間接的にTargetSample.dllinternalにアクセスできるというわけです。

実験

dllを作成する

Riderで適当なdllを生成します。このとき重要なのはHogeという名前のアセンブリからのみinternalにアクセスできるようにしておきます。

using System.Runtime.CompilerServices;

[assembly: InternalsVisibleTo("Hoge")]

namespace TargetSample
{
    public class SampleClass
    {
        public int PublicMethod()
        {
            return 1;
        }

        internal int InternalMethod()
        {
            return 2;
        }

        private int PrivateMethod()
        {
            return 3;
        }
    }   
}

生成したdllをUnityにインポートしておきます。

生成したdllをインポート

Hoge.asmdefを定義する

Hoge.asmdefからは当然TargetSample.dllinternalにアクセスすることが可能です。

private void Start()
{
    var sampleClass = new SampleClass();

    // 当然publicにアクセスできる
    sampleClass.PublicMethod();
        
    // internalにアクセスできる
    sampleClass.InternalMethod();
        
    // privateにはアクセスできない
    // sampleClass.PrivateMethod();
}
Hoge.asmdef

asmrefでHoge.asmdefにコードを組み込む

asmrefを用いてHoge.asmdefにコードを組み込むことで間接的にinternalをアクセスしていきます。

asmrefを定義する
private void Start()
{
    var sampleClass = new SampleClass();
        
    // asmrefでHoge.asmdefにコードが組み込まれるのでinternalにアクセスできる
    sampleClass.InternalMethod();
}

さいごに

リフレクションは処理が重いだけでなく、コンパイル時にエラーが出てこなかったりとなるべく使いたくないものです。internalということはそれだけ変更もされやすいというわけで、常に危険に晒されています。

Unityが提供するdllinternalにアクセスしたいなどの場合に、ぜひ試してみてください。