2012年9月22日星期六

TypeConverter学习

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>)));

动态的为类添加TypeConvert。

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


TAG: