C#で今風メタプログラミング。Expression Tree(式木)に慣れ親しもう。
久しぶりにExpression Tree(式木)をいじってました。
.NET Framework4では式木が大幅にバージョンアップして、複文や条件分岐、ループなどが表現できるようになりましたが、
それによってどんな面白いことができるかは、まだ模索中だったりします。
今回はとりあえず、.NET Framework3.5の式木で可能な範囲という前提で式木で遊んでみました。
System.Reflectionを使わずにpublicメソッドのMethodInfoを取得、
あるいはprivateメソッドのMethodInfoをReflectionで取得し、それをもとにタイプセーフなデリゲートの生成などをしています。
MethodInfoExtentions
MethodInfoからExpresiion Treeを用いてデリゲートの生成などをしています。
何度も同じ式木をこねくりまわすのは効率がよろしくないだろうということで、メモ化してみました。
とはいえ、メモ化として機能するケースは、TInstanceがImmutableオブジェクトである場合か
Staticメソッドが対象である場合に限られるので、ほとんどのケースでは式木をこねることになります。
って、実装した後に気付きましたが、実はメモ化などせず何も考えずに毎回こねた方が高速かもしれませんorz
using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Reflection; namespace ClassLibrary1 { /// <summary> /// MethodInfoExtentions /// </summary> public static class MethodInfoExtentions { #region デリゲートの生成 #region Action public static Action CreateAction<TInstance> (this MethodInfo self, TInstance instance) { var dic = CreateSingletonDictionary(new { x = default(MethodInfo), y = default(TInstance) } , new { x = default(Action)}); var instanceParam = CreateParameterExpression(typeof(TInstance),"target")(); var ce = CreateMethodCallEpressions(self, instanceParam); var key = new { x = self, y = instance }; return () => { if (dic.ContainsKey(key)) { dic[key].x(); return; } var lambda = Expression.Lambda<Action<TInstance>>( Expression.Convert(ce, typeof(void)), instanceParam); var f = dic[key] = new { x = lambda.Compile().Curry()(instance) }; f.x(); }; } public static Action<TArgs1> CreateAction<TInstance, TArgs1> (this MethodInfo self,TInstance instance) { var dic = CreateSingletonDictionary(new { x = default(MethodInfo), y = default(TInstance) } , new { x = default(Action<TArgs1>) }); var instanceParam = CreateParameterExpression(typeof(TInstance), "target")(); var arg1 = CreateParameterExpression(typeof(TArgs1), "arg1")(); var ce = CreateMethodCallEpressions(self, instanceParam, arg1); var key = new { x = self, y = instance }; return x => { if (dic.ContainsKey(key)) { dic[key].x(x); return; } var lambda = Expression.Lambda<Action<TInstance, TArgs1>>( Expression.Convert(ce, typeof(void)),instanceParam, arg1); var f = dic[key] = new { x = lambda.Compile().Curry()(instance) }; f.x(x); }; } public static Action<TArgs1, TArgs2> CreateAction<TInstance, TArgs1, TArgs2> (this MethodInfo self, TInstance instance) { var dic = CreateSingletonDictionary(new { x = default(MethodInfo), y = default(TInstance) } , new { x = default(Action<TArgs1, TArgs2>) }); var instanceParam = CreateParameterExpression(typeof(TInstance), "target")(); var arg1 = CreateParameterExpression(typeof(TArgs1), "arg1")(); var arg2 = CreateParameterExpression(typeof(TArgs2), "arg2")(); var ce = CreateMethodCallEpressions(self, instanceParam, arg1, arg2); var key = new { x = self, y = instance }; return (x,y) => { if (dic.ContainsKey(key)) { dic[key].x(x,y); return; } var lambda = Expression.Lambda<Action<TInstance, TArgs1, TArgs2>>( Expression.Convert(ce, typeof(void)), instanceParam, arg1, arg2); var f = dic[key] = new { x = lambda.Compile().Curry()(instance) }; f.x(x,y); }; } public static Action<TArgs1, TArgs2, TArgs3> CreateAction<TInstance, TArgs1, TArgs2, TArgs3> (this MethodInfo self, TInstance instance) { var dic = CreateSingletonDictionary(new { x = default(MethodInfo), y = default(TInstance) } , new { x = default(Action<TArgs1, TArgs2, TArgs3>) }); var instanceParam = CreateParameterExpression(typeof(TInstance), "target")(); var arg1 = CreateParameterExpression(typeof(TArgs1), "arg1")(); var arg2 = CreateParameterExpression(typeof(TArgs2), "arg2")(); var arg3 = CreateParameterExpression(typeof(TArgs3), "arg3")(); var ce = CreateMethodCallEpressions(self, instanceParam, arg1, arg2, arg3); var key = new { x = self, y = instance }; return (x, y, z) => { if (dic.ContainsKey(key)) { dic[key].x(x, y, z); return; } var lambda = Expression.Lambda<Action<TInstance, TArgs1, TArgs2, TArgs3>>( Expression.Convert(ce, typeof(void)), instanceParam, arg1, arg2, arg3); var f = dic[key] = new { x = lambda.Compile().Curry()(instance) }; f.x(x, y, z); }; } #endregion #region Func public static Func<TResult> CreateFunc<TInstance, TResult> (this MethodInfo self, TInstance instance) { var dic = CreateSingletonDictionary(new { x = default(MethodInfo), y = default(TInstance) } , new { x = default(Func<TResult>) }); var instanceParam = CreateParameterExpression(typeof(TInstance), "target")(); var ce = CreateMethodCallEpressions(self, instanceParam); var key = new { x = self, y = instance }; return () => { if (dic.ContainsKey(key)) return dic[key].x(); var lambda = Expression.Lambda<Func<TInstance, TResult>>( Expression.Convert(ce, typeof(TResult)), instanceParam); var f = dic[key] = new { x = lambda.Compile().Curry()(instance) }; return f.x(); }; } public static Func<TArgs1, TResult> CreateFunc<TInstance, TArgs1, TResult> (this MethodInfo self, TInstance instance) { var dic = CreateSingletonDictionary(new { x = default(MethodInfo), y = default(TInstance) } , new { x = default(Func<TArgs1, TResult>) }); var instanceParam = CreateParameterExpression(typeof(TInstance), "target")(); var arg1 = CreateParameterExpression(typeof(TArgs1), "arg1")(); var ce = CreateMethodCallEpressions(self, instanceParam, arg1); var key = new { x = self, y = instance }; return x => { if (dic.ContainsKey(key)) return dic[key].x(x); var lambda = Expression.Lambda<Func<TInstance, TArgs1, TResult>>( Expression.Convert(ce, typeof(TResult)), instanceParam, arg1); var f = dic[key] = new { x = lambda.Compile().Curry()(instance) }; return f.x(x); }; } public static Func<TArgs1, TArgs2, TResult> CreateFunc<TInstance, TArgs1, TArgs2, TResult> (this MethodInfo self, TInstance instance) { var dic = CreateSingletonDictionary(new { x = default(MethodInfo), y = default(TInstance) } , new { x = default(Func<TArgs1, TArgs2, TResult>) }); var instanceParam = CreateParameterExpression(typeof(TInstance), "target")(); var arg1 = CreateParameterExpression(typeof(TArgs1), "arg1")(); var arg2 = CreateParameterExpression(typeof(TArgs2), "arg2")(); var ce = CreateMethodCallEpressions(self, instanceParam, arg1, arg2); var key = new { x = self, y = instance }; return (x,y) => { if (dic.ContainsKey(key)) return dic[key].x(x, y); var lambda = Expression.Lambda<Func<TInstance, TArgs1, TArgs2, TResult>>( Expression.Convert(ce, typeof(TResult)), instanceParam, arg1, arg2); var f = dic[key] = new { x = lambda.Compile().Curry()(instance) }; return f.x(x,y); }; } public static Func<TArgs1, TArgs2, TArgs3, TResult> CreateFunc<TInstance, TArgs1, TArgs2, TArgs3, TResult> (this MethodInfo self, TInstance instance) { var dic = CreateSingletonDictionary(new { x = default(MethodInfo), y = default(TInstance) } , new { x = default(Func<TArgs1, TArgs2, TArgs3, TResult>) }); var instanceParam = CreateParameterExpression(typeof(TInstance), "target")(); var arg1 = CreateParameterExpression(typeof(TArgs1), "arg1")(); var arg2 = CreateParameterExpression(typeof(TArgs2), "arg2")(); var arg3 = CreateParameterExpression(typeof(TArgs3), "arg3")(); var ce = CreateMethodCallEpressions(self, instanceParam, arg1, arg2, arg3); var key = new { x = self, y = instance }; return (x, y, z) => { if (dic.ContainsKey(key)) return dic[key].x(x, y, z); var lambda = Expression.Lambda<Func<TInstance, TArgs1, TArgs2, TArgs3, TResult>>( Expression.Convert(ce, typeof(TResult)), instanceParam, arg1, arg2, arg3); var f = dic[key] = new { x = lambda.Compile().Curry()(instance) }; return f.x(x, y, z); }; } #endregion #endregion #region 引数の型と数が曖昧模糊なデリゲートの生成 public static Action<object[]> CreateVagueAction<TInstance> (this MethodInfo self, TInstance instance) { var dic = CreateSingletonDictionary(new { x = default(MethodInfo), y = default(TInstance) } , new { x = default(Action<object[]>) }); var instanceParam = Expression.Parameter(typeof(TInstance), "target"); var args = Expression.Parameter(typeof(object[]), "arguments"); var ce = CreateMethodCallEpressions(self, instanceParam, args); var key = new { x = self, y = instance }; return x => { if (dic.ContainsKey(key)) { dic[key].x(x); return; } var lambda = Expression.Lambda<Action<TInstance, object[]>>( Expression.Convert(ce, typeof(void)), instanceParam, args); var f = dic[key] = new { x = lambda.Compile().Curry()(instance) }; f.x(x); }; } public static Func<object[], TResult> CreateVagueFunc<TInstance, TResult> (this MethodInfo self, TInstance instance) { var dic = CreateSingletonDictionary(new { x = default(MethodInfo), y = default(TInstance) } , new { x = default(Func<object[], TResult>) }); var instanceParam = Expression.Parameter(typeof(TInstance), "target"); var args = Expression.Parameter(typeof(object[]), "args"); var ce = CreateMethodCallEpressions(self, instanceParam, args); var key = new { x = self, y = instance }; return x => { if (dic.ContainsKey(key)) return dic[key].x(x); var lambda = Expression.Lambda<Func<TInstance, object[], TResult>>( Expression.Convert(ce, typeof(TResult)), instanceParam, args); var f = dic[key] = new { x = lambda.Compile().Curry()(instance) }; return f.x(x); }; } #endregion private static MethodCallExpression CreateMethodCallEpressions (MethodInfo method, ParameterExpression instanceParam, ParameterExpression argParam) { if (method.IsStatic) return Expression.Call(method, CreateParameterExpressions(method, argParam)); return Expression.Call(Expression.Convert(instanceParam, method.DeclaringType) , method , CreateParameterExpressions(method, argParam)); } private static MethodCallExpression CreateMethodCallEpressions (MethodInfo method, ParameterExpression instanceParam, params ParameterExpression[] argParam) { if (method.IsStatic) return Expression.Call(method, CreateParameterExpressions(method, argParam)); return Expression.Call(Expression.Convert(instanceParam, method.DeclaringType) , method , CreateParameterExpressions(method, argParam)); } private static Func<ParameterExpression> CreateParameterExpression(Type type, string name) { var dic = CreateSingletonDictionary(new { x = default(Type), y = default(string) } , new { x = default(ParameterExpression)}); return () => { var key = new { x = type, y = name }; if (dic.ContainsKey(key)) return dic[key].x; dic[key] = new { x = Expression.Parameter(type, name) }; return dic[key].x; }; } private static Expression[] CreateParameterExpressions(MethodInfo method, Expression argParam) { if (argParam.Type.IsArray) return method.GetParameters().Select((param, index) => Expression.Convert(Expression.ArrayIndex(argParam, Expression.Constant(index)) , param.ParameterType)).ToArray(); return method.GetParameters().Select((param, index) => Expression.Convert(argParam, param.ParameterType)).ToArray(); } private static Expression[] CreateParameterExpressions(MethodInfo method, params Expression[] argParam) { return method.GetParameters().Select((param, index) => Expression.Convert(argParam[index] , param.ParameterType)).ToArray(); } public static Dictionary<T, U> CreateSingletonDictionary<T, U>() { return Singleton<Dictionary<T, U>>.Instance; } public static Dictionary<T, U> CreateSingletonDictionary<T, U>(T tDummy) { return Singleton<Dictionary<T, U>>.Instance; } public static Dictionary<T, U> CreateSingletonDictionary<T, U>(T tDummy, U uDummy) { return Singleton<Dictionary<T, U>>.Instance; } } public static class Singleton<T> where T : class, new() { private static T _t = new T(); public static T Instance { get { return _t; } } } }
カリー化
カリー化です。MethodInfoExtentionsにて、
各種デリゲートを生成する際にTInstanceとさよならするために使っています。
using System; namespace ClassLibrary1 { //C#3.0ではこれが必要 //public delegate TResult Func<T1, T2, T3, T4, T5, TResult>(T1 a, T2 b, T3 c, T4 d, T5 e); /// <summary> /// カリー化を提供します。 /// </summary> public static class CurryExtentions { #region ActionCurry /// <summary> /// Action{TArgs1}についてカリー化します。 /// </summary> /// <typeparam name="TArgs1"></typeparam> /// <param name="f"></param> /// <returns></returns> public static Func<TArgs1, Action> Curry<TArgs1> (this Action<TArgs1> f) { return a => () => f(a); } /// <summary> /// Action{TArgs1, TArgs2}についてカリー化します。 /// </summary> /// <typeparam name="TArgs1"></typeparam> /// <typeparam name="TArgs2"></typeparam> /// <param name="f"></param> /// <returns></returns> public static Func<TArgs1,Action<TArgs2>> Curry<TArgs1, TArgs2> (this Action<TArgs1, TArgs2> f) { return a => b => f(a,b); } /// <summary> /// Action{TArgs1, TArgs2, TArgs3}についてカリー化します。 /// </summary> /// <typeparam name="TArgs1"></typeparam> /// <typeparam name="TArgs2"></typeparam> /// <typeparam name="TArgs3"></typeparam> /// <param name="f"></param> /// <returns></returns> public static Func<TArgs1, Action<TArgs2, TArgs3>> Curry<TArgs1, TArgs2, TArgs3> (this Action<TArgs1, TArgs2, TArgs3> f) { return a => (b, c) => f(a, b, c); } /// <summary> /// Action{TArgs1, TArgs2, TArgs3, TArgs4}についてカリー化します。 /// </summary> /// <typeparam name="TArgs1"></typeparam> /// <typeparam name="TArgs2"></typeparam> /// <typeparam name="TArgs3"></typeparam> /// <typeparam name="TArgs4"></typeparam> /// <param name="f"></param> /// <returns></returns> public static Func<TArgs1, Action<TArgs2, TArgs3, TArgs4>> Curry<TArgs1, TArgs2, TArgs3, TArgs4> (this Action<TArgs1, TArgs2, TArgs3, TArgs4> f) { return a => (b, c, d) => f(a, b, c, d); } /// <summary> /// Action{TArgs1, TArgs2, TArgs3, TArgs4, TArgs5}についてカリー化します。 /// </summary> /// <typeparam name="TArgs1"></typeparam> /// <typeparam name="TArgs2"></typeparam> /// <typeparam name="TArgs3"></typeparam> /// <typeparam name="TArgs4"></typeparam> /// <typeparam name="TArgs5"></typeparam> /// <param name="f"></param> /// <returns></returns> public static Func<TArgs1, Action<TArgs2, TArgs3, TArgs4, TArgs5>> Curry<TArgs1, TArgs2, TArgs3, TArgs4, TArgs5> (this Action<TArgs1, TArgs2, TArgs3, TArgs4, TArgs5> f) { return a => (b, c, d, e) => f.Curry()(a)(b, c, d, e); } #endregion #region FuncCurry /// <summary> /// Func{TArgs1, TResult}についてカリー化します。 /// </summary> /// <typeparam name="TArgs1"></typeparam> /// <typeparam name="TResult"></typeparam> /// <param name="f"></param> /// <returns></returns> public static Func<TArgs1, Func<TResult>> Curry<TArgs1, TResult> (this Func<TArgs1, TResult> f) { return a => () => f(a); } /// <summary> /// Func{TArgs1, TArgs2, TResult}についてカリー化します。 /// </summary> /// <typeparam name="TArgs1"></typeparam> /// <typeparam name="TArgs2"></typeparam> /// <typeparam name="TResult"></typeparam> /// <param name="f"></param> /// <returns></returns> public static Func<TArgs1, Func<TArgs2, TResult>> Curry<TArgs1, TArgs2, TResult> (this Func<TArgs1, TArgs2, TResult> f) { return a => b => f(a, b); } /// <summary> /// Func{TArgs1, TArgs2, TArgs3, TResult}についてカリー化します。 /// </summary> /// <typeparam name="TArgs1"></typeparam> /// <typeparam name="TArgs2"></typeparam> /// <typeparam name="TArgs3"></typeparam> /// <typeparam name="TResult"></typeparam> /// <param name="f"></param> /// <returns></returns> public static Func<TArgs1, Func<TArgs2, TArgs3, TResult>> Curry<TArgs1, TArgs2, TArgs3, TResult> (this Func<TArgs1, TArgs2, TArgs3, TResult> f) { return a => (b,c) => f(a,b,c); } /// <summary> /// Func{TArgs1, TArgs2, TArgs3, TArgs4, TResult}についてカリー化します。 /// </summary> /// <typeparam name="TArgs1"></typeparam> /// <typeparam name="TArgs2"></typeparam> /// <typeparam name="TArgs3"></typeparam> /// <typeparam name="TArgs4"></typeparam> /// <typeparam name="TResult"></typeparam> /// <param name="f"></param> /// <returns></returns> public static Func<TArgs1, Func<TArgs2, TArgs3, TArgs4, TResult>> Curry<TArgs1, TArgs2, TArgs3, TArgs4, TResult> (this Func<TArgs1, TArgs2, TArgs3, TArgs4, TResult> f) { return a => (b, c, d) => f(a, b, c, d); } /// <summary> /// Func{TArgs1, TArgs2, TArgs3, TArgs4, TArgs5, TResult}についてカリー化します。 /// </summary> /// <typeparam name="TArgs1"></typeparam> /// <typeparam name="TArgs2"></typeparam> /// <typeparam name="TArgs3"></typeparam> /// <typeparam name="TArgs4"></typeparam> /// <typeparam name="TArgs5"></typeparam> /// <typeparam name="TResult"></typeparam> /// <param name="f"></param> /// <returns></returns> public static Func<TArgs1, Func<TArgs2, TArgs3, TArgs4, TArgs5, TResult>> Curry<TArgs1, TArgs2, TArgs3, TArgs4, TArgs5, TResult> (this Func<TArgs1, TArgs2, TArgs3, TArgs4, TArgs5, TResult> f) { return a => (b , c , d , e) => f(a, b, c, d, e); } #endregion } }
りふれくたー
そもそも、PublicメソッドのMethodInfoが欲しいようなケースはほとんどないわけなんですが、
こねくりまわした式木からタイプセーフなデリゲートとか作りたい場合なんかには有用かもしれません。
using System; using System.Linq.Expressions; using System.Reflection; namespace ClassLibrary1 { /// <summary> /// Reflector /// </summary> public static class Reflector { #region MethodInfo取得 #region Action MethodInfo public static MethodInfo Action(Expression<Action> method) { return GetMethodInfo(method); } public static MethodInfo Action<TInstance>(Expression<Action<TInstance>> method) { return GetMethodInfo(method); } public static MethodInfo Action<TInstance, TArgs1>(Expression<Action<TInstance, TArgs1>> method) { return GetMethodInfo(method); } public static MethodInfo Action<TInstance, TArgs1, TArgs2>(Expression<Action<TInstance, TArgs1, TArgs2>> method) { return GetMethodInfo(method); } public static MethodInfo Action<TInstance, TArgs1, TArgs2, TArgs3>(Expression<Action<TInstance, TArgs1, TArgs2, TArgs3>> method) { return GetMethodInfo(method); } #endregion #region Func MethodInfo public static MethodInfo Func<TResult>(Expression<Func<TResult>> method) { return GetMethodInfo(method); } public static MethodInfo Func<TInstance, TResult>(Expression<Func<TInstance, TResult>> method) { return GetMethodInfo(method); } public static MethodInfo Func<TInstance, TArgs1, TResult>(Expression<Func<TInstance, TArgs1, TResult>> method) { return GetMethodInfo(method); } public static MethodInfo Func<TInstance, TArgs1, TArgs2, TResult>(Expression<Func<TInstance, TArgs1, TArgs2, TResult>> method) { return GetMethodInfo(method); } public static MethodInfo Func<TInstance, TArgs1, TArgs2, TArgs3, TResult>(Expression<Func<TInstance, TArgs1, TArgs2, TArgs3, TResult>> method) { return GetMethodInfo(method); } #endregion #endregion #region デリゲートの生成 #region Action public static Action CreateAction<TInstance> (Expression<Action<TInstance>> method, TInstance instance) { return GetMethodInfo(method).CreateAction<TInstance>(instance); } public static Action<TArgs1> CreateAction<TArgs1, TInstance> (Expression<Action<TArgs1, TInstance>> method, TInstance instance) { return GetMethodInfo(method).CreateAction<TInstance, TArgs1>(instance); } public static Action<TArgs1, TArgs2> CreateAction<TArgs1, TArgs2, TInstance> (Expression<Action<TArgs1, TArgs2, TInstance>> method, TInstance instance) { return GetMethodInfo(method).CreateAction<TInstance, TArgs1, TArgs2>(instance); } public static Action<TArgs1, TArgs2, TArgs3> CreateAction<TArgs1, TArgs2, TArgs3, TInstance> (Expression<Action<TArgs1, TArgs2, TArgs3, TInstance>> method, TInstance instance) { return GetMethodInfo(method).CreateAction<TInstance, TArgs1, TArgs2, TArgs3>(instance); } #endregion #region Func public static Func<TResult> CreateFunc<TResult, TInstance> (Expression<Func<TInstance, TResult>> method, TInstance instance) { return GetMethodInfo(method).CreateFunc<TInstance, TResult>(instance); } public static Func<TArgs1, TResult> CreateFunc<TArgs1, TResult, TInstance> (Expression<Func<TInstance, TArgs1, TResult>> method, TInstance instance) { return GetMethodInfo(method).CreateFunc<TInstance, TArgs1, TResult>(instance); } public static Func<TArgs1, TArgs2, TResult> CreateFunc<TArgs1, TArgs2, TResult, TInstance> (Expression<Func<TInstance, TArgs1, TArgs2, TResult>> method, TInstance instance) { return GetMethodInfo(method).CreateFunc<TInstance, TArgs1, TArgs2, TResult>(instance); } public static Func<TArgs1, TArgs2, TArgs3, TResult> CreateFunc<TArgs1, TArgs2, TArgs3, TResult, TInstance> (Expression<Func<TInstance, TArgs1, TArgs2, TArgs3, TResult>> method, TInstance instance) { return GetMethodInfo(method).CreateFunc<TInstance, TArgs1, TArgs2, TArgs3, TResult>(instance); } #endregion #endregion /// <summary> /// ExpressionからMethodInfoを取得します。 /// </summary> /// <param name="expression"></param> /// <returns></returns> private static MethodInfo GetMethodInfo(Expression expression) { var lambda = expression as LambdaExpression; if (lambda == null) throw new ArgumentException("expression"); MethodCallExpression methodExpr = null; if (lambda.Body.NodeType == ExpressionType.Convert) { methodExpr = ((UnaryExpression)lambda.Body).Operand as MethodCallExpression; } else if (lambda.Body.NodeType == ExpressionType.Invoke || lambda.Body.NodeType == ExpressionType.Call) { methodExpr = lambda.Body as MethodCallExpression; } if (methodExpr == null) throw new ArgumentException("expression"); return methodExpr.Method; } } }
お試し
VS2010のテストで。
using System.Diagnostics; using System.Reflection; using Microsoft.VisualStudio.TestTools.UnitTesting; using ClassLibrary1; namespace TestProject1 { /// <summary> /// UnitTest1 の概要の説明 /// </summary> [TestClass] public class UnitTest1 { public UnitTest1() { } private TestContext testContextInstance; /// <summary> ///現在のテストの実行についての情報および機能を ///提供するテスト コンテキストを取得または設定します。 ///</summary> public TestContext TestContext { get { return testContextInstance; } set { testContextInstance = value; } } #region Private Test [TestMethod] public void PrivateAction() { var hoge = new Hoge(); var method = hoge.GetType().GetMethod("PrivateAction", BindingFlags.NonPublic | BindingFlags.Instance); var dgt = method.CreateAction<Hoge>(hoge); dgt(); } [TestMethod] public void PrivateAction1() { var hoge = new Hoge(); var method = hoge.GetType().GetMethod("PrivateAction1", BindingFlags.NonPublic | BindingFlags.Instance); var dgt = method.CreateAction<Hoge,string>(hoge); dgt("hoge"); } [TestMethod] public void PrivateAction2() { var hoge = new Hoge(); var method = hoge.GetType().GetMethod("PrivateAction2", BindingFlags.NonPublic | BindingFlags.Instance); var dgt = method.CreateAction<Hoge, string, string>(hoge); dgt("hoge", "fuga"); } [TestMethod] public void PrivateAction3() { var hoge = new Hoge(); var method = hoge.GetType().GetMethod("PrivateAction3", BindingFlags.NonPublic | BindingFlags.Instance); var dgt = method.CreateAction<Hoge, string, string, string>(hoge); dgt("hoge", "fuga", "piyo"); } [TestMethod] public void PrivateFunc() { var hoge = new Hoge(); var method = hoge.GetType().GetMethod("PrivateFunc", BindingFlags.NonPublic | BindingFlags.Instance); var dgt = method.CreateFunc<Hoge, string>(hoge); Assert.IsTrue(dgt() == "Func"); } [TestMethod] public void PrivateFunc1() { var hoge = new Hoge(); var method = hoge.GetType().GetMethod("PrivateFunc1", BindingFlags.NonPublic | BindingFlags.Instance); var dgt = method.CreateFunc<Hoge, string, string>(hoge); Assert.IsTrue(dgt("Func1") == "Func1"); } [TestMethod] public void PrivateFunc2() { var hoge = new Hoge(); var method = hoge.GetType().GetMethod("PrivateFunc2", BindingFlags.NonPublic | BindingFlags.Instance); var dgt = method.CreateFunc<Hoge, string, string, string>(hoge); Assert.IsTrue(dgt("Func1", "Func2") == "Func1Func2"); } [TestMethod] public void PrivateFunc3() { var hoge = new Hoge(); var method = hoge.GetType().GetMethod("PrivateFunc3", BindingFlags.NonPublic | BindingFlags.Instance); var dgt = method.CreateFunc<Hoge, string, string, string, string>(hoge); Assert.IsTrue(dgt("Func1", "Func2", "Func3") == "Func1Func2Func3"); } #endregion #region Public Test [TestMethod] public void PublicAction() { var hoge = new Hoge(); var dgt = Reflector.CreateAction<Hoge>(x => hoge.Action(), hoge); dgt(); } [TestMethod] public void PublicAction1() { var hoge = new Hoge(); var dgt = Reflector.CreateAction<string, Hoge>((x,y) => hoge.Action1(x), hoge); dgt("aaa"); } [TestMethod] public void PublicAction2() { var hoge = new Hoge(); var dgt = Reflector.CreateAction<string, string, Hoge>((x, y, z) => hoge.Action2(x,y), hoge); dgt("aaa", "bbb"); } [TestMethod] public void PublicAction3() { var hoge = new Hoge(); var dgt = Reflector.CreateAction<string ,string, string, Hoge>((x, y, z, a) => hoge.Action3(x, y, z), hoge); dgt("aaa", "bbb", "ccc"); } [TestMethod] public void PublicFunc() { var hoge = new Hoge(); var dgt = Reflector.CreateFunc<string, Hoge>(x => x.Func(), hoge); Assert.IsTrue(dgt() == "Func"); } [TestMethod] public void PublicFunc1() { var hoge = new Hoge(); var dgt = Reflector.CreateFunc<string, string, Hoge>((x,y) => x.Func1(y), hoge); Assert.IsTrue(dgt("Func1") == "Func1"); } [TestMethod] public void PublicFunc2() { var hoge = new Hoge(); var dgt = Reflector.CreateFunc<string, string, string, Hoge>((x, y, z) => x.Func2(y, z), hoge); Assert.IsTrue(dgt("Func1","Func2") == "Func1Func2"); } [TestMethod] public void PublicFunc3() { var hoge = new Hoge(); var dgt = Reflector.CreateFunc<string, string, string, string, Hoge>((x, y, z, a) => x.Func3(y, z, a), hoge); Assert.IsTrue(dgt("Func1", "Func2", "Func3") == "Func1Func2Func3"); } #endregion #region Static Test [TestMethod] public void StaticAction() { var dgt = Reflector.CreateAction<Hoge>(x => Hoge.StaticAction(), null); dgt(); } [TestMethod] public void StaticAction1() { var dgt = Reflector.CreateAction<string, Hoge>((x, y) => Hoge.StaticAction1(x), null); dgt("aaa"); } [TestMethod] public void StaticAction2() { var dgt = Reflector.CreateAction<string, string, Hoge>((x, y, z) => Hoge.StaticAction2(x, y), null); dgt("aaa", "bbb"); } [TestMethod] public void StaticAction3() { var dgt = Reflector.CreateAction<string, string, string, Hoge>((x, y, z, a) => Hoge.StaticAction3(x, y, z), null); dgt("aaa", "bbb", "ccc"); } [TestMethod] public void StaticFunc() { var dgt = Reflector.CreateFunc<string, Hoge>(x => Hoge.StaticFunc(), null); Assert.IsTrue(dgt() == "StaticFunc"); } [TestMethod] public void StaticFunc1() { var dgt = Reflector.CreateFunc<string, string, Hoge>((x, y) => Hoge.StaticFunc1(y), null); Assert.IsTrue(dgt("Func1") == "Func1"); } [TestMethod] public void StaticFunc2() { var dgt = Reflector.CreateFunc<string, string, string, Hoge>((x, y, z) => Hoge.StaticFunc2(y, z), null); Assert.IsTrue(dgt("Func1", "Func2") == "Func1Func2"); } [TestMethod] public void StaticFunc3() { var dgt = Reflector.CreateFunc<string, string, string, string, Hoge>((x, y, z, a) => Hoge.StaticFunc3(y, z, a), null); Assert.IsTrue(dgt("Func1", "Func2", "Func3") == "Func1Func2Func3"); } #endregion class Hoge { #region Public #region Action public void Action() { Debug.Print("PrivateAction"); } public void Action1(string arg1) { Debug.Print(arg1); } public void Action2(string arg1, string arg2) { Debug.Print(arg1 + arg2); } public void Action3(string arg1, string arg2, string arg3) { Debug.Print(arg1 + arg2 + arg3); } #endregion #region Func public string Func() { return "Func"; } public string Func1(string arg1) { return arg1; } public string Func2(string arg1, string arg2) { return arg1 + arg2; } public string Func3(string arg1, string arg2, string arg3) { return arg1 + arg2 + arg3; } #endregion #endregion #region Private #region Action private void PrivateAction() { Debug.Print("Action"); } private void PrivateAction1(string arg1) { Debug.Print(arg1); } private void PrivateAction2(string arg1, string arg2) { Debug.Print(arg1 + arg2); } private void PrivateAction3(string arg1, string arg2, string arg3) { Debug.Print(arg1 + arg2 + arg3); } #endregion #region Func private string PrivateFunc() { return "Func"; } private string PrivateFunc1(string arg1) { return arg1; } private string PrivateFunc2(string arg1, string arg2) { return arg1 + arg2; } private string PrivateFunc3(string arg1, string arg2, string arg3) { return arg1 + arg2 + arg3; } #endregion #endregion #region Static public static void StaticAction() { Debug.Print("StaticAction"); } public static void StaticAction1(string arg1) { Debug.Print(arg1); } public static void StaticAction2(string arg1, string arg2) { Debug.Print(arg1 + arg2); } public static void StaticAction3(string arg1, string arg2, string arg3) { Debug.Print(arg1 + arg2 + arg3); } public static string StaticFunc() { return "StaticFunc"; } public static string StaticFunc1(string arg1) { return arg1; } public static string StaticFunc2(string arg1, string arg2) { return arg1 + arg2; } public static string StaticFunc3(string arg1, string arg2, string arg3) { return arg1 + arg2 + arg3; } #endregion } } }
実用性は微妙だけど式木をこねるいい練習になりました。
メタプログラミングは楽しいなー。また暇をみていろいろやってみる。