之前的一个 封装读取配置文件类 中,CommonHelper.To() 方法实现类型的转换,用到了TypeConverter 类。学习记录一下用法。
TypeConverter 实现两个类的互相转换。 通过继承TypeConverter按需实现4个方法来实现自定义类型转换。
public
virtual
object
ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture,
object
value)
public
virtual
object
ConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture,
object
value, System.Type destinationType)
public
virtual
bool
CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType)
public
virtual
bool
CanConvertTo(ITypeDescriptorContext context, Type destinationType)
GenericListTypeConverter.cs
using
System;
using
System.Collections.Generic;
using
System.ComponentModel;
using
System.Globalization;
using
System.Linq;
namespace
Nop.Core.ComponentModel
{
public
class
GenericListTypeConverter<T>
: TypeConverter
{
protected
readonly
TypeConverter _typeConverter;
public
GenericListTypeConverter()
{
_typeConverter
= TypeDescriptor.GetConverter(
typeof
(T));
if
(_typeConverter ==
null
)
throw
new
InvalidOperationException(
"
No type converter exists for type
"
+
typeof
(T).FullName);
}
protected
virtual
string
[] GetStringArray(
string
input)
{
if
(!
String.IsNullOrEmpty(input))
{
string
[] result = input.Split(
'
,
'
);
Array.ForEach(result, s
=>
s.Trim());
return
result;
}
else
return
new
string
[
0
];
}
public
override
bool
CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if
(sourceType ==
typeof
(
string
))
{
string
[] items =
GetStringArray(sourceType.ToString());
return
(items.Count() >
0
);
}
return
base
.CanConvertFrom(context, sourceType);
}
public
override
object
ConvertFrom(ITypeDescriptorContext context, CultureInfo culture,
object
value)
{
if
(value
is
string
)
{
string
[] items = GetStringArray((
string
)value);
var
result =
new
List<T>
();
Array.ForEach(items, s
=>
{
object
item =
_typeConverter.ConvertFromInvariantString(s);
if
(item !=
null
)
{
result.Add((T)item);
}
});
return
result;
}
return
base
.ConvertFrom(context, culture, value);
}
public
override
object
ConvertTo(ITypeDescriptorContext context, CultureInfo culture,
object
value, Type destinationType)
{
if
(destinationType ==
typeof
(
string
))
{
string
result =
string
.Empty;
if
(((IList<T>)value) !=
null
)
{
//
we don't use string.Join() because it doesn't support invariant culture
for
(
int
i =
0
; i < ((IList<T>)value).Count; i++
)
{
var
str1 = Convert.ToString(((IList<T>
)value)[i], CultureInfo.InvariantCulture);
result
+=
str1;
//
don't add comma after the last element
if
(i != ((IList<T>)value).Count -
1
)
result
+=
"
,
"
;
}
}
return
result;
}
return
base
.ConvertTo(context, culture, value, destinationType);
}
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) { if ((destinationType == typeof (List<T>)) | (destinationType == typeof (InstanceDescriptor))) return true ; else return base .CanConvertTo(context, destinationType); }} }
Test代码
[Test]
public
void
CanConvertFromTest1()
{
TypeConverter typeConverter
=
new
GenericListTypeConverter<
string
>
();
var
items =
"
10,20,30,40,50
"
;
var
list =
new
List<
string
>
();
if
(typeConverter.CanConvertFrom(
typeof
(
string
)))
{
list
= typeConverter.ConvertFrom(items)
as
List<
string
>
;
}
Assert.AreEqual(list.Count,
5
);
}
[Test]
public
void
CanConvertToTest1()
{
var
items =
new
List<
string
> {
"
foo
"
,
"
bar
"
,
"
day
"
};
string
result =
""
;
TypeConverter typeConverter
=
new
GenericListTypeConverter<
string
>
();
result
= typeConverter.ConvertTo(items,
typeof
(
string
))
as
string
;
Assert.True(result.Length
>
0
);
}
GenericListTypeConverter实现了 string,List<string>的互相转换。
上面的代码需要new 一个 TypeConverter方法来实现转换。另一种方法是使用Attribute特性附加在Class中,如下
[TypeConverter(
typeof
(Triangle.TriangleConverter))]
public
class
Triangle
{
}
这样做方便设计时和运行时实现转换。
//
获取该类的TypeConvert实例
var
typeConvert = TypeDescriptor.GetConverter(
typeof
(Longitude))
如果有一下的需求,该如何使用TypeConvert?
1.如何为类库中的类添加特性。
2.根据动态的为类添加TypeConvert。
3.为泛型类添加TypeConvert。
如下
TypeDescriptor.AddAttributes(
typeof
(List<
string
>
),
new
TypeConverterAttribute(
typeof
(GenericListTypeConverter<
string
>)));
Test代码:
[SetUp]
public
void
SetUp()
{
TypeDescriptor.AddAttributes(
typeof
(List<
int
>
),
new
TypeConverterAttribute(
typeof
(GenericListTypeConverter<
int
>
)));
TypeDescriptor.AddAttributes(
typeof
(List<
string
>
),
new
TypeConverterAttribute(
typeof
(GenericListTypeConverter<
string
>
)));
}
[Test]
public
void
Can_get_int_list_type_converter()
{
var
converter = TypeDescriptor.GetConverter(
typeof
(List<
int
>
));
converter.GetType().ShouldEqual(
typeof
(GenericListTypeConverter<
int
>
));
}
[Test]
public
void
Can_get_string_list_type_converter()
{
var
converter = TypeDescriptor.GetConverter(
typeof
(List<
string
>
));
converter.GetType().ShouldEqual(
typeof
(GenericListTypeConverter<
string
>
));
}
[Test]
public
void
Can_get_int_list_from_string()
{
var
items =
"
10,20,30,40,50
"
;
var
converter = TypeDescriptor.GetConverter(
typeof
(List<
int
>
));
var
result = converter.ConvertFrom(items)
as
IList<
int
>
;
result.ShouldNotBeNull();
result.Count.ShouldEqual(
5
);
}
[Test]
public
void
Can_get_string_list_from_string()
{
var
items =
"
foo, bar, day
"
;
var
converter = TypeDescriptor.GetConverter(
typeof
(List<
string
>
));
var
result = converter.ConvertFrom(items)
as
List<
string
>
;
result.ShouldNotBeNull();
result.Count.ShouldEqual(
3
);
}
参考:
http://www.cnblogs.com/ericwen/archive/2007/12/12/typeconvertattribute.html

