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