代码改变世界

Caliburn笔记-方法(IMethod)的创建(wpf框架)

2009-12-25 11:44  Clingingboy  阅读(748)  评论(0编辑  收藏  举报

为了适应框架的需要,对原生的MethodInfo进行了改造,如下图

image 

我们可以看到,主要的功能点是允许方法可以进行异步操作.其次IMethod也继承了IMetadataContainer接口,在方法上使用元数据也非常普遍.如下为默认实现的抽象类

/// <summary>
/// A base class for <see cref="IMethod"/> implementations.
/// </summary>
private abstract class MethodProxyBase : MetadataContainer, IMethod
{
    private readonly MethodInfo _info;
    protected readonly IThreadPool _threadPool;

    /// <summary>
    /// Initializes a new instance of the <see cref="MethodProxyBase"/> class.
    /// </summary>
    /// <param name="info">The info.</param>
    /// <param name="threadPool">The thread pool.</param>
    protected MethodProxyBase(MethodInfo info, IThreadPool threadPool)
    {
        _info = info;
        _threadPool = threadPool;

        AddMetadataFrom(_info);
    }

    /// <summary>
    /// Gets the <see cref="MethodInfo"/> to which this instance applies.
    /// </summary>
    /// <value>The info.</value>
    public MethodInfo Info
    {
        get { return _info; }
    }

    /// <summary>
    /// Invokes the specified method on the provided instance with the given parameters.
    /// </summary>
    /// <param name="instance">The instance.</param>
    /// <param name="parameters">The parameters.</param>
    /// <returns>
    /// The result of the function or null if it is a procedure.
    /// </returns>
    public abstract object Invoke(object instance, params object[] parameters);

    /// <summary>
    /// Creates a background task for executing this method asynchronously.
    /// </summary>
    /// <param name="instance">The instance.</param>
    /// <param name="parameters">The parameters.</param>
    /// <returns>
    /// An instance of <see cref="IBackgroundTask"/>.
    /// </returns>
    public abstract IBackgroundTask CreateBackgroundTask(object instance, params object[] parameters);


继承此类的分为有返回值与无返回值的方法

关键点:

  1. 对方法进行了委托转换
  2. 方法执行安全操作,可进行抛错
  3. 可以进行异步
private class Function : MethodProxyBase
{
    private readonly LateBoundFunc _theDelegate;

    /// <summary>
    /// Initializes a new instance of the <see cref="Function"/> class.
    /// </summary>
    /// <param name="info">The info.</param>
    /// <param name="threadPool">The thread pool.</param>
    public Function(MethodInfo info, IThreadPool threadPool)
        : base(info, threadPool)
    {
        _theDelegate = DelegateFactory.Create<LateBoundFunc>(info);
    }

    /// <summary>
    /// Invokes the specified method on the provided instance with the given parameters.
    /// </summary>
    /// <param name="instance">The instance.</param>
    /// <param name="parameters">The parameters.</param>
    /// <returns>
    /// The result of the function or null if it is a procedure.
    /// </returns>
    public override object Invoke(object instance, params object[] parameters)
    {
        return SafeInvoke(instance, parameters);
    }

    /// <summary>
    /// Creates a background task for executing this method asynchronously.
    /// </summary>
    /// <param name="instance">The instance.</param>
    /// <param name="parameters">The parameters.</param>
    /// <returns>
    /// An instance of <see cref="IBackgroundTask"/>.
    /// </returns>
    public override IBackgroundTask CreateBackgroundTask(object instance, params object[] parameters)
    {
        return new BackgroundTask(_threadPool, () => SafeInvoke(instance, parameters));
    }

    private object SafeInvoke(object instance, object[] parameters)
    {
        try
        {
            return _theDelegate(instance, parameters);
        }
        catch(Exception)
        {
            var requirements = Info.GetParameters();

            if (requirements.Length != parameters.Length)
                throw new CaliburnException(
                    string.Format(
                        "The method '{0}' expected {1} parameters but was provided {2}.",
                        Info.Name,
                        requirements.Length,
                        parameters.Length)
                    );
            throw;
        }
    }
}


DelegateFactory用于动态转换委托,其使用了表达式树(Expression)动态进行编译.