id:neueccさんに影響されて(ミーハー)Expression Treeをこねてみました。
やりたいことは以下のコードです。
var vm = new ViewModel(); // ここの下一行をExpression Treeで組みたい vm.HogeCommand = new DelegateCommand<int>(vm.HogeExecute, vm.CanHogeExecute);
id:neueccさんのやり方を参考にこねこねした結果、以下のようなコードになりました。
namespace ConsoleApplication2 { using System; using System.Linq.Expressions; using System.Reflection; // ダミーコマンド public class DelegateCommand<T> { public DelegateCommand(Action<T> a, Func<T, bool> b) { } } // ダミーViewModel public class ViewModel { public DelegateCommand<int> HogeCommand { get; set; } public void HogeExecute(int i) { Console.WriteLine("OK"); } public bool CanHogeExecute(int i) { return true; } } class Program { static void Main(string[] args) { // ViewModel型のHogeCommandを初期化するアクションを作成する var initHogeCommandAction = CreateInitCommandAction<ViewModel>("HogeCommand"); // ViewModelを作ってコマンドの初期化をしてもらう var model = new ViewModel(); initHogeCommandAction(model); // 初期化出来てるか表示してみる(nullじゃなくなってるはず) Console.WriteLine(model.HogeCommand); } static Action<TViewModel> CreateInitCommandAction<TViewModel>(string commandName) { // CreateDelegateのMethodInfoを作る var createDelegate = typeof(Delegate).GetMethod( "CreateDelegate", new[] { typeof(Type), typeof(object), typeof(MethodInfo) }); // ExecuteのMethodInfoの変数 var execMethod = typeof(TViewModel).GetMethod(commandName.Replace("Command", "Execute")); var execVar = Expression.Constant(execMethod); // CanExecuteのMethodInfoの変数 var canExecMethod = typeof(TViewModel).GetMethod("Can" + commandName.Replace("Command", "Execute")); var canExecVar = Expression.Constant(canExecMethod); // コマンドのパラメータタイプ var argumentType = execMethod.GetParameters()[0].ParameterType; // パラメータ型を指定したActionとFuncの型を取得 var actionType = Expression.GetActionType(argumentType); var canExecuteActionType = Expression.GetFuncType(argumentType, typeof(bool)); // DelegateCommandのコンストラクタを取得 var delConstructor = typeof(DelegateCommand<>) .MakeGenericType(argumentType).GetConstructor( new[] { actionType, canExecuteActionType }); // パラメータはTViewModel型 var param = Expression.Parameter(typeof(TViewModel)); // Executeメソッドのデリゲートを作成する式 var createExecDelegate = Expression.Call( createDelegate, Expression.Constant(actionType), param, execVar); // CanExecuteメソッドのデリゲートを作成する式 var createCanExecDelegate = Expression.Call( createDelegate, Expression.Constant(canExecuteActionType), param, canExecVar); var lambda = Expression.Lambda<Action<TViewModel>>( Expression.Assign( // コマンドのプロパティに Expression.PropertyOrField(param, commandName), // DelegateCommandのインスタンスを設定 Expression.New( delConstructor, Expression.Convert(createExecDelegate, actionType), Expression.Convert(createCanExecDelegate, canExecuteActionType))), param); // コンパイル!! return lambda.Compile(); } } }
たったの一行のコードなのにExpression Treeにすると凄い長いです!!!まぁ、あの一行が暗黙的にDelegate作ったりとか色々やってるんだなというのがわかった今日この頃でした。頭が疲れました。