摘要:在前一篇文章中我们并没有考虑配置的组件参数是什么类型,也没有在配置文件中指定过类型,那么Castle IOC是如何进行类型转换的?如何配置一些复杂的数据类型?如果有自定义的类型如何去进行类型转换?本文将进行一一解答这些问题。
主要内容
1.基本类型配置
2.Array类型配置
3.List类型配置
4.Dictionary类型配置
5.自定义类型转换
一.基本类型配置
在Castle IOC的配置文件中,大家可能都已经注意一个问题了,就是不管组件接收的是什么基本数据类型,我们一律没有在配置文件中指定,也就是说,不管组件接收的类型是int型或者是String类型,我们都可以这样去配置:
<
component
id
="MyComponent"
>
![None.gif](/Images/OutliningIndicators/None.gif)
<
parameters
>
![None.gif](/Images/OutliningIndicators/None.gif)
<
port
>
10
</
port
>
![None.gif](/Images/OutliningIndicators/None.gif)
</
parameters
>
![None.gif](/Images/OutliningIndicators/None.gif)
</
component
>
这是因为在Castle IOC中,MicroKernel中的SubSystem中有一个TypeConverter,它专门负责类型的转换。参数的注入一般都是通过构造函数或者公有的属性,基本数据类型在配置文件我们不需要用专门的节点去配置,但是对于一些复杂的数据类型久有些不一样。目前Castle IOC能够支持的数据类型如下。
类型 | 节点 | 示例 |
System.Int32, Int16, Int64 | - | <parameters> <port>10</port> </parameters> |
System.UInt32, UInt16, UInt64 | - | <parameters> <port>10</port> </parameters> |
System.Char | - | <parameters> <letter>a</letter> </parameters> |
System.Single, Double, Decimal | - | <parameters> <threshold>13.22</threshold> </parameters> |
System.String | - | <parameters> <server>mail.host.com</server> </parameters> |
System.Byte, SByte | - | <parameters> <rcolor>144</rcolor> </parameters> |
System.Boolean | - | <parameters> <enabled>0</enabled> </parameters> |
System.DateTime | - | <parameters> <initial>11022005</initial> </parameters> |
System.Type | - | <parameters> <type>Components.MyComponent, Components</type> </parameters> |
System.Array | array | 参见后面 |
System.Collections.IList | list | 参见后面 |
System.Collections.IDictionary | dictionary | 参见后面 |
如果有其它的类型,我们需要编写自定义的TypeConverter。
二.Array类型配置
组件构造函数有一个Array的参数
//
出处:
http://terrylee.cnblogs.com
public
class
MyComponent
![ExpandedBlockStart.gif](/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
private int[] orders;
![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
public int[]Orders
![ExpandedSubBlockStart.gif](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
![ExpandedSubBlockStart.gif](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get
{ return this.orders;}
}
public MyComponent()
![ExpandedSubBlockStart.gif](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
}
public MyComponent(int[]orders)
![ExpandedSubBlockStart.gif](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
this.orders = orders;
}
}
这时候我们的配置文件可以如下去写
<!--
出处:http://terrylee.cnblogs.com
-->
![None.gif](/Images/OutliningIndicators/None.gif)
<?
xml version="1.0" encoding="utf-8"
?>
![None.gif](/Images/OutliningIndicators/None.gif)
<
configuration
>
![None.gif](/Images/OutliningIndicators/None.gif)
<
component
id
="e"
type
="CastleDemo.MyComponent,CastleDemo"
>
![None.gif](/Images/OutliningIndicators/None.gif)
<
parameters
>
![None.gif](/Images/OutliningIndicators/None.gif)
<
Orders
>
![None.gif](/Images/OutliningIndicators/None.gif)
<
item
type
="System.Int32"
>
![None.gif](/Images/OutliningIndicators/None.gif)
<
item
>
1
</
item
>
![None.gif](/Images/OutliningIndicators/None.gif)
<
item
>
2
</
item
>
![None.gif](/Images/OutliningIndicators/None.gif)
<
item
>
3
</
item
>
![None.gif](/Images/OutliningIndicators/None.gif)
</
item
>
![None.gif](/Images/OutliningIndicators/None.gif)
</
Orders
>
![None.gif](/Images/OutliningIndicators/None.gif)
</
parameters
>
![None.gif](/Images/OutliningIndicators/None.gif)
</
component
>
![None.gif](/Images/OutliningIndicators/None.gif)
</
configuration
>
三.List类型配置
组件构造函数有一个IList类型的参数
//
出处:
http://terrylee.cnblogs.com
public
class
MyComponent
![ExpandedBlockStart.gif](/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
private IList _hosts;
![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
public MyComponent(IList hosts)
![ExpandedSubBlockStart.gif](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
this._hosts = hosts;
}
![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
public IList Hosts
![ExpandedSubBlockStart.gif](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
![ExpandedSubBlockStart.gif](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get
{ return _hosts; }
}
//![dot.gif](https://www.cnblogs.com/Images/dot.gif)
![dot.gif](https://www.cnblogs.com/Images/dot.gif)
}
这时候我们的配置文件应该如下
<!--
出处:http://terrylee.cnblogs.com
-->
![None.gif](/Images/OutliningIndicators/None.gif)
<?
xml version="1.0" encoding="utf-8"
?>
![None.gif](/Images/OutliningIndicators/None.gif)
<
configuration
>
![None.gif](/Images/OutliningIndicators/None.gif)
<
component
id
="mycomponent"
type
="CastleDemo.MyComponent,CastleDemo"
>
![None.gif](/Images/OutliningIndicators/None.gif)
<
parameters
>
![None.gif](/Images/OutliningIndicators/None.gif)
<
hosts
>
![None.gif](/Images/OutliningIndicators/None.gif)
<
list
type
="System.String"
>
![None.gif](/Images/OutliningIndicators/None.gif)
<
item
>
server1
</
item
>
![None.gif](/Images/OutliningIndicators/None.gif)
<
item
>
server2
</
item
>
![None.gif](/Images/OutliningIndicators/None.gif)
<
item
>
server3
</
item
>
![None.gif](/Images/OutliningIndicators/None.gif)
<
item
>
server4
</
item
>
![None.gif](/Images/OutliningIndicators/None.gif)
</
list
>
![None.gif](/Images/OutliningIndicators/None.gif)
</
hosts
>
![None.gif](/Images/OutliningIndicators/None.gif)
</
parameters
>
![None.gif](/Images/OutliningIndicators/None.gif)
</
component
>
![None.gif](/Images/OutliningIndicators/None.gif)
</
configuration
>
四.Dictionary类型配置
组件构造函数有一个Idictionary类型的参数
//
出处:
http://terrylee.cnblogs.com
public
class
MyComponent
![ExpandedBlockStart.gif](/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
private IDictionary _dictionary;
![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
public MyComponent(IDictionary d)
![ExpandedSubBlockStart.gif](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
this._dictionary = d;
}
![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
public IDictionary Dictionary
![ExpandedSubBlockStart.gif](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
![ExpandedSubBlockStart.gif](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get
{ return this._dictionary;}
}
//![dot.gif](https://www.cnblogs.com/Images/dot.gif)
![dot.gif](https://www.cnblogs.com/Images/dot.gif)
}
配置文件应该如下去写:
<!--
出处:http://terrylee.cnblogs.com
-->
![None.gif](/Images/OutliningIndicators/None.gif)
<?
xml version="1.0" encoding="utf-8"
?>
![None.gif](/Images/OutliningIndicators/None.gif)
<
configuration
>
![None.gif](/Images/OutliningIndicators/None.gif)
<
component
id
="MyComponent"
type
="CastleDemo.MyComponent,CastleDemo"
>
![None.gif](/Images/OutliningIndicators/None.gif)
<
parameters
>
![None.gif](/Images/OutliningIndicators/None.gif)
<
d
>
![None.gif](/Images/OutliningIndicators/None.gif)
<
dictionary
>
![None.gif](/Images/OutliningIndicators/None.gif)
<
entry
key
="a"
>
a
</
entry
>
![None.gif](/Images/OutliningIndicators/None.gif)
<
entry
key
="b"
>
b
</
entry
>
![None.gif](/Images/OutliningIndicators/None.gif)
<
entry
key
="c"
>
c
</
entry
>
![None.gif](/Images/OutliningIndicators/None.gif)
</
dictionary
>
![None.gif](/Images/OutliningIndicators/None.gif)
</
d
>
![None.gif](/Images/OutliningIndicators/None.gif)
</
parameters
>
![None.gif](/Images/OutliningIndicators/None.gif)
</
component
>
![None.gif](/Images/OutliningIndicators/None.gif)
</
configuration
>
或者我们可以在配置文件中分别指定Key和Value的数据类型,分别使用keyType和valueType。
<!--
出处:http://terrylee.cnblogs.com
-->
![None.gif](/Images/OutliningIndicators/None.gif)
<?
xml version="1.0" encoding="utf-8"
?>
![None.gif](/Images/OutliningIndicators/None.gif)
<
configuration
>
![None.gif](/Images/OutliningIndicators/None.gif)
<
component
id
="MyComponent"
type
="CastleDemo.MyComponent,CastleDemo"
>
![None.gif](/Images/OutliningIndicators/None.gif)
<
parameters
>
![None.gif](/Images/OutliningIndicators/None.gif)
<
d
>
![None.gif](/Images/OutliningIndicators/None.gif)
<
dictionary
keyType
="System.String, mscorlib"
valueType
="System.String, mscorlib"
>
![None.gif](/Images/OutliningIndicators/None.gif)
<
entry
key
="a"
>
a
</
entry
>
![None.gif](/Images/OutliningIndicators/None.gif)
<
entry
key
="b"
>
b
</
entry
>
![None.gif](/Images/OutliningIndicators/None.gif)
<
entry
key
="c"
>
c
</
entry
>
![None.gif](/Images/OutliningIndicators/None.gif)
</
dictionary
>
![None.gif](/Images/OutliningIndicators/None.gif)
</
d
>
![None.gif](/Images/OutliningIndicators/None.gif)
</
parameters
>
![None.gif](/Images/OutliningIndicators/None.gif)
</
component
>
![None.gif](/Images/OutliningIndicators/None.gif)
</
configuration
>
五.自定义类型转换
要实现我们自定义的类型转换,在这之前我们还是花一点时间来看看Castle IOC中是如何实现类型的转换的。在SubSystems中有一个Conversion,专门负责类型的转换,通过一个类型转换器ConversionManager来实现对类型转换的管理,在DefaultConversionManager初始化的时候,会加载以下几个类型转换:
protected
virtual
void
InitDefaultConverters()
![ExpandedBlockStart.gif](/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
Add( new PrimitiveConverter() );
![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
Add( new TypeNameConverter() );
![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
Add( new EnumConverter() );
![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
Add( new ListConverter() );
![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
Add( new DictionaryConverter() );
![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
Add( new ArrayConverter() );
![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
}
这些类型转换器之间的结构图如下:
![](https://images.cnblogs.com/cnblogs_com/terrylee/CastleIOC_03.jpg)
图1
PrimitiveConverter:负责基本数据类型的转换
TypeNameConverter:负责把一个类型的名字转换成这个类型的实例
EnumConverter:负责枚举类型的转换
ListConverter:负责Ilist数据类型的转换
DictionaryConverter:负责Idictionary数据类型转换
ArrayConverter:负责Array数据类型转换
以其中的PrimitiveConverter为例来看一下它的实现代码:
public
class
PrimitiveConverter : AbstractTypeConverter
![ExpandedBlockStart.gif](/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
private Type[] types;
![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
public PrimitiveConverter()
![ExpandedSubBlockStart.gif](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
types = new Type[]
![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
![ExpandedSubBlockStart.gif](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
typeof (Char),
![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
typeof (DateTime),
![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
typeof (Decimal),
![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
typeof (Boolean),
![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
typeof (Int16),
![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
typeof (Int32),
![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
typeof (Int64),
![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
typeof (UInt16),
![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
typeof (UInt32),
![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
typeof (UInt64),
![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
typeof (Byte),
![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
typeof (SByte),
![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
typeof (Single),
![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
typeof (Double),
![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
typeof (String)
![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
};
}
![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
public override bool CanHandleType(Type type)
![ExpandedSubBlockStart.gif](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
return Array.IndexOf(types, type) != -1;
}
![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
public override object PerformConversion(String value, Type targetType)
![ExpandedSubBlockStart.gif](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
if (targetType == typeof(String)) return value;
![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
try
![ExpandedSubBlockStart.gif](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
return Convert.ChangeType(value, targetType);
![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
}
catch(Exception ex)
![ExpandedSubBlockStart.gif](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
String message = String.Format(
![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
"Could not convert from '{0}' to {1}",
![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
value, targetType.FullName);
![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
throw new ConverterException(message, ex);
![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
}
![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
}
![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
public override object PerformConversion(IConfiguration configuration, Type targetType)
![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
![ExpandedSubBlockStart.gif](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
return PerformConversion(configuration.Value, targetType);
![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
}
![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
}
可以看到,Castle IOC会把所有的配置参数都当作String类型接收,如果目标类型是String,则直接返回结果,否则再进行类型转换。由此我们可以分析得出,要实现自己的类型转换,有以下两步:
1.编写的自己的类型转换类,实现接口ITypeConverter
//
出处:
http://terrylee.cnblogs.com
public
class
MyTypeConverter : ITypeConverter
![ExpandedBlockStart.gif](/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
//![dot.gif](https://www.cnblogs.com/Images/dot.gif)
![dot.gif](https://www.cnblogs.com/Images/dot.gif)
}
2.添加自己的类型转换到ConversionManager中
IKernel kernel
=
new
DefaultKernel();
![None.gif](/Images/OutliningIndicators/None.gif)
IConversionManager conversionMng
=
(IConversionManager)
![None.gif](/Images/OutliningIndicators/None.gif)
kernel.GetSubSystem( SubSystemConstants.ConversionManagerKey );
![None.gif](/Images/OutliningIndicators/None.gif)
conversionMng.Add(
new
MyTypeConverter());
关于Castle IOC容器中构建配置信息就到这里了,我总共分为了一,二两部分来讲解。Castle IOC系列的文章后续还有很多,希望大家继续关注!
参考资料
Castle的官方网站http://www.castleproject.org