Mono.Cecil调用泛型类型构造函数

时间:2013-05-15 16:07:19

标签: .net generics mono.cecil

使用Mono.Cecil我注入了一个类似这样的类型:

internal class InjectedDelegateCommand<TParameter> : ICommand {
    // Fields
    private readonly Predicate<TParameter> _canExecute;
    private readonly Action<TParameter> _execute;

    // Events
    public event EventHandler CanExecuteChanged {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    // Methods
    public InjectedDelegateCommand(Action<TParameter> execute) : this(execute, null){}

    public InjectedDelegateCommand(Action<TParameter> execute, Predicate<TParameter> canExecute) {
        if (execute == null) {
            throw new ArgumentNullException("execute");
        }
        this._execute = execute;
        this._canExecute = canExecute;
    }

    public bool CanExecute(object parameter) {
        return ((this._canExecute == null) || this._canExecute((TParameter) parameter));
    }

    public void Execute(object parameter) {
        this._execute((TParameter) parameter);
    }
}

我现在需要注入一些代码来用这个命令类型初始化一个类的属性,即:。

public class ViewModel {
    public ViewModel(){
        SubmitCommand = new InjectedDelegateCommand<string>(
            new Action<string>(OnSubmit)
            , new Predicate<string>(CanSubmit));
    } 

    public ICommand SubmitCommand {get; set;}
    public void OnSubmit(string parameter){}
    public bool CanSubmit(string parameter) {
        return true;
    }
}

不幸的是,我似乎无法理解如何在cecil中正确实现构造函数调用。

有人可以帮忙吗?我对IL需要生成什么感兴趣,而不是如何为构造函数获取正确的MethodReference来实现这些行:

        SubmitCommand = new InjectedDelegateCommand<string>(
            new Action<string>(OnSubmit)
            , new Predicate<string>(CanSubmit));

编辑 - 包括我尝试过的内容。

我已经尝试编写下面的方法来获取我想要使用的构造函数,但泛型是错误的:

private MethodReference GetConstructorResolved(MethodReference commandConstructor, MethodDefinition method)
{
    var parameterType = method.HasParameters
        ? method.Parameters[0].ParameterType
        : Assets.TypeReferences.Object;

    var commandType = commandConstructor.DeclaringType;
    bool isGeneric = commandType.HasGenericParameters;
    if (commandType.HasGenericParameters)
    {
        var commandTypeResolved = commandConstructor.DeclaringType.MakeGenericInstanceType(parameterType);
        commandType = commandTypeResolved;
        var resolvedConstructor =
            commandType.GetElementType()
                .Resolve()
                .GetConstructors()
                .First(c => c.Parameters.Count == commandConstructor.Parameters.Count);
        commandConstructor = resolvedConstructor;
    }

    if (isGeneric)
    {
        if (method.HasParameters)
        {
            commandConstructor =
                commandConstructor.MakeHostInstanceGeneric(method.Parameters[0].ParameterType);
        }
        else
        {
            commandConstructor = commandConstructor.MakeHostInstanceGeneric(Assets.TypeReferences.Object);
        }
    }
    return commandConstructor;
}

MakeHostGeneric来自此处:https://stackoverflow.com/a/16433452/203499

我最终看起来像IL一样(注意在这个例子中我试图只调用单个参数构造函数,因为如果我能弄明白我可以找出2个参数) :

IL_0013: ldftn instance void WpfMvvmSample.ViewModel::Submit(string)
IL_0019: newobj instance void class [mscorlib]System.Action`1<string>::.ctor(object, native int)
IL_001e: newobj instance void class 'InjectedDelegateCommand'<string>::.ctor(class [mscorlib]System.Action`1<!0>)
IL_0023: call instance void WpfMvvmSample.ViewModel::set_SubmitCommand(class [PresentationCore]System.Windows.Input.ICommand)

0 个答案:

没有答案