之前的一个 封装读取配置文件类 中,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