主にプログラミング関連のメモ帳 ♪(✿╹ヮ╹)ノ
書いてあるコードは自己責任でご自由にどうぞ。記事本文の無断転載は禁止です。
2022/05/29
たとえば以下のような ref
パラメータを持ったメソッドがあったとして、
private static void ShaderErrorListUI(Shader shader, ShaderMessage[] messages, ref Vector2 scrollPosition)
{
// ...
}
これをリフレクション経由で呼びたい場合は、多分普通に作るとこうなる。
var t = typeof(typeof(Editor).Assembly.GetType("UnityEditor.ShaderInspector));
var m = t.GetMethod("ShaderErrorListUI", BindingFlags.NonPublic | BindingFlags.Static);
m.Invoke(null, new object[] { shader, messages, scrollPosition });
ただ、これだとパフォーマンス的にあまりよくないので、式木を使ってこんな感じにするとする。
var args = Expression.Parameter(typeof(object[]), "args");
var body = m.GetParameters().Select((w, i) => Expression.Convert(Expression.ArrayIndex(args, Expression.Constant(i)), w.ParameterType)).Cast<Expression>().ToArray();
var call = Expression.Call(null, m, body);
var invoke = Expression.Lambda<Action<object[]>>(body, args).Compile();
invoke.Invoke(new object[] { shader, messages, scrollPosition });
こうすると式木は 1 度だけコンパイルされるのでリフレクションよりは早く動く......のだけど、実は呼び出し時エラーになる。
System.ArgumentException: Type must not be ByRef (Parameter 'type')
というのも、実は ref
みたいな引数にパラメータが付いている場合は、 T
に対して MakeByRefType()
が呼ばれたメソッドなので、キャストできない。
ということで、以下のように ParameterType
の所に、下記のようなメソッドを挟んであげると良い。
private static Type UnpackType(Type t)
{
if (t.IsByRef)
return t.GetElementType();
return t;
}
ということで、メモでした。