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

posted @ 2012-09-22 19:21  不夜橙  阅读(1174)  评论(0编辑  收藏  举报