9.95 XML Inline Parameters

优质
小牛编辑
133浏览
2023-12-01

When using XML configuration it is possible to specify various dependencies for the components.

Simple parameters

:information_source: Parameter names are not case sensitive: All names of the parameters are not case sensitive so no matter if you specify foo, FOO or Foo Windsor will process them the same.

<component
   id="ping"
   type="Acme.Crm.Services.PingService, Acme.Crm">
   <parameters>
      <pingServer>http://acme.org</pingServer>
      <pingInterval>00:00:30</pingInterval>
      <pingRetries>3</pingRetries>
      <pingNotificator>${emailSender}</pingNotificator>
   </parameters>
</component>

Simple parameters are parameters of simple types, like primitives, Uris, DateTimes, TimeSpans, Types, enums or service overrides. These are parameters that have their value expressed as simple content of the enclosing name tag.

:information_source: How parameter types are matched: Windsor does not require you to specify type of the parameter you provide. Instead, when resolving the component it will try to match the dependency on the component by name (case insensitive), and see if it can convert the parameter value to the the type of the dependency.

Complex parameters

Complex parameters are ones that consist of more than one element. For example if you want to specify in XML parameter, named pingServerInfo of the following type:

[Convertible]
public class ServerInfo
{
   private readonly Uri address;

   public ServerInfo(Uri address)
   {
      this.address = address;
   }

   public Uri Address
   {
      get { return address; }
   }

   public int Port { get; set; }
}

you can do it thusly:

<parameters>
   <pingServerInfo>
      <parameters>
         <address>http://localhost</address>
         <port>80</port>
      </parameters>
   </pingServerInfo>
</parameters>

:information_source: The ConvertibleAttribute attribute: You may have noticed the [Convertible] attribute on ServerInfo class. Currently when you're using complex parameter it is required that you tell Windsor explicitly, that this type is parameter, not a service.

Lists

Assuming you have the component:

public class MyComponent
{
   public MyComponent(IEnumerable<Uri> info)
   {
      Info = info;
   }

   public IEnumerable<Uri> Info { get; private set; }
}

You can pass the info collection as list, specifying it in config:

<parameters>
   <info>
      <list>
         <item>http://localhost:80</item>
         <item>http://castleproject.org</item>
      </list>
   </info>
</parameters>

Notice we specified the parameter as IEnumerable<Uri> passing in a list. We also didn't have to specify any types. Windsor inferred correct type from generic parameter of the IEnumerable<>.

:information_source: Non-generic collections: If we would use non-generic collection (IList or IEnumerable) we'd get collection of strings, instead of Uris, since then Windsor would not have enough information to correctly guess the type of the items in the collection. In this case, we have to be explicit:

<list type="System.Uri, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">

Arrays

Arrays are almost identical to lists. If instead of list, in the above example we wanted an array, we'd have to configure it as follows:

<parameters>
   <info>
      <array>
         <item>http://localhost:80</item>
         <item>http://castleproject.org</item>
      </array>
   </info>
</parameters>

Dictionaries

In addition to lists and arrays, also dictionaries are supported. If we specified info to be IDictionary<string, Uri> we would use the following configuration:

<parameters>
   <info>
      <dictionary>
         <entry key="local">http://localhost:80</entry>
         <entry key="castle">http://castleproject.org</entry>
      </dictionary>
   </info>
</parameters>

:information_source: Untyped dictionary: If you used untyped, non-generic dictionary Windsor would default to using strings for key and value types. If that is not what you want, you can specify their types explicitly via keyType and valueType attributes respectively, similarly to how you'd do it for list. You can specify these attributes at dictionary level, or at entry level.

Custom parameter types

If built in converters don't suit your needs, you can always supply your own implementation. To do so, you need to create type implementing ITypeConverter (you can inherit abstract base implementation AbstractTypeConverter) and plug it into conversion subsystem of the container:

var manager = (IConversionManager)container.Kernel.GetSubSystem(SubSystemConstants.ConversionManagerKey);
manager.Add(new MyConfigConverter());