使用方法的返回值进行注入

本节要讲的第三个类是MethodInvokingFactoryObject。MethodInvokingFactoryObject允许使用任意方法的返回值进行注入。

MethodInvokingFactoryObject类可以处理实例方法和静态方法。此外,Spring.NET中另有一种处理对象初始化的机制(参考4.5.1.1,IInitializingObject接口和init-method属性)也可以用来进行(初始化)方法的调用,但是用这种机制调用方法的目的只是进行初始化工作,并且不允许向方法中传递任何参数,调用的时机也被限制在对象被容器创建时。MethodInvokingFactoryObject类则允许在任意时刻调用任意对象的任意方法(或者任意类的静态方法)。

在下面的例子中,使用MethodInvokingFactoryObject类强制在myService对象创建之前调用一个静态方法。

<object id="force-init"
type="Spring.Objects.Factory.Config.MethodInvokingFactoryObject, Spring.Core">
<property name="TargetMethod" value="Initialize">
<property name="TargetType" value="ExampleNamespace.ExampleInitializerClass, ExampleAssembly">
</object>

<object id="myService" type="MyService" depends-on="force-init"/>

(按:原文中上面的例子似有错误,此处已做修正;具体可参考英文文档)

注意对象定义myService的depends-on属性引用了一个名为force-init的MethodInvokingFactoryObject对象,该引用会使对象force-init在myService之前初始化(并且调用force-init的目标类型上的目标方法。注意,若要使这个配置正常工作,myService对象必须以singleton模式操作(按:否则myService对象只会在请求时创建,而此时force-init已经被容器预先创建了,也就失去了depends-on的意义)——这也是默认的对象布署模式,参见下一章)。

MethodInvokingFactoryObject类也可用于访问工厂方法(按:当在代码中通过名称"force-init"从容器中获取对象时,如果其目标方法有返回值,那么获得的对象就是目标方法的返回值;如果目标方法返回null,那么获得对象的类型则是System.Reflecton.Missing),一般情况下,工厂方法都是以singleton模式操作的。如果MethodInvokingFactoryObject对象为singleton模式,那么在它所有属性被设置后(按:应该是设置了足够的属性后,即TargetType和TargetMethod),目标方法会立即被调用并将返回值存入缓存以备用。随后,如果容器向此工厂请求对象,那么返回的将是缓存中的值。MethodInvokingFactoryObject对象的singleton属性可以设置为false,此时每次请求对象都会去调用目标方法(返回值不会被缓存)。

在MethodInvokingFactoryObject的对象定义中,用TargetMethod和TargetType属性指定目标静态方法名和方法所在的类型全名;而用TargetMethod和TargetObject属性来指定目标实例方法名和方法所在对象的引用。

目标方法的参数可以通过两种方式来设置(这两种方式可混合使用)。第一种是通过Arguments属性来指定参数列表。注意列表中项的顺序是很重要的——必须和方法签名中的参数列表在次序上完全一致,且类型兼容,如下例:

<object id="myObject" type="Spring.Objects.Factory.Config.MethodInvokingFactoryObject, Spring.Core">
  <property name="TargetType" value="Whatever.MyClassFactory, MyAssembly"/>
  <property name="TargetMethod" value="GetInstance"/>
  
  <!-- the ordering of arguments is significant -->
  <property name="Arguments">
    <list>

      <value>1st</value>
      <value>2nd</value>
      <value>and 3rd arguments</value>
      <!-- automatic Type-conversion will be performed prior to invoking the method -->

    </list>
  </property>
</object>

第二种方式是通过NamedArguments属性配置一系列键/值对,其中键名对应参数名(文本类型),值对应参数值(可以是任意对象)。参数名是大小写不敏感的,并且顺序(当然)是不重要的(因为词典类型本身就没有顺序)。见下面的例子:

<object id="myObject" type="Spring.Objects.Factory.Config.MethodInvokingFactoryObject, Spring.Core">
  <property name="TargetObject">
    <object type="Whatever.MyClassFactory, MyAssembly"/>
  </property>
  <property name="TargetMethod" value="Execute"/>
  
  <!-- the ordering of named arguments is not significant -->

  <property name="NamedArguments">
    <dictionary>
      <entry key="argumentName"><value>1st</value></entry>
      <entry key="finalArgumentName"><value>and 3rd arguments</value></entry>

      <entry key="anotherArgumentName"><value>2nd</value></entry>
    </dictionary>
  </property>
</object>

下面使用MethodInvokingFactoryObject来调用一个实例方法:

<object id="myMethodObject" type="Whatever.MyClassFactory, MyAssembly" />

<object id="myObject" type="Spring.Objects.Factory.Config.MethodInvokingFactoryObject, Spring.Core">
  <property name="TargetObject" ref="myMethodObject"/>
  <property name="TargetMethod" value="Execute"/>
</object>

上例中的目标对象也可以是匿名的内联对象定义...如果对象的方法不会在工厂对象之外调用,那么最好通过内联对象定义将目标方法限制在工厂对象内部。

最后要注意,如果使用MethodInvokingFactoryObject来调用一个有变长参数列表的方法,必须使用list来按顺序定义要传递的参数值。请看下面的例子,其中CreateObject方法的参数arguments是用C#关键字params来定义的;随后是相应的XML配置:

[C#]
public class MyClassFactory
{
    public object CreateObject(Type objectType, params string[] arguments)
    {
        return ... // implementation elided for clarity...
    }
}
<object id="myMethodObject" type="Whatever.MyClassFactory, MyAssembly" />
				
<object id="paramsMethodObject" type="Spring.Objects.Factory.Config.MethodInvokingFactoryObject, Spring.Core">
  <property name="TargetObject" ref="myMethodObject"/>
  <property name="TargetMethod" value="CreateObject"/>
  <property name="Arguments">
    <list>

      <value>System.String</value>
      <!-- here is the 'params string[] arguments' -->
      <list>
        <value>1st</value>
        <value>2nd</value>

      </list>
    </list>
</object>
posted @ 2011-10-17 13:29  attitudedecidesall  Views(517)  Comments(0Edit  收藏  举报