• 深度解析 TypeConverter & TypeConverterAttribute (一)


    前言
        我们在开发复杂控件的时候不可避免的碰到类型转换TypeConverter,微软给我们提供了很多转换类如 ArrayConverter,BaseNumberConverter,BooleanConverter(MSDN上更多:ms- help://MS.MSDNQTR.v80.en/MS.MSDN.v80/MS.NETDEVFX.v20.en/cpref3/html /N_System_ComponentModel.htm)等直接或间接的继承了TypeConverter类。我们在类型转换的时候经常用到这些类。 然而我们如何编写自定义的TypeConverter类呢,又怎么样在复杂控件中使用呢。

    TypeConverter Class
       
    TypeConverter类就是将一种类型(object,可以说是任何类型)转换到另一种类型(一般为string),或者将另一种类型转换回来。所有继承TypeConverter类型的都必须实现4个方法:(这里以另一种类型string为例)
        CanConverterTo 有两个重载方法,
                 TypeConverter.CanConvertTo (Type)
                 TypeConverter.CanConvertTo (ITypeDescriptorContext, Type)
           都有一个Type参数(要转换成什么类型),例如我们设计的要转换成string,在方法体里面判断这个参数的Type如果是string,则返回true,否则返回           false
        ConverterTo 也有两重载,
                 TypeConverter.ConvertTo (Object, Type)
                 TypeConverter.ConvertTo (ITypeDescriptorContext, CultureInfo, Object, Type)
           都有Object和Type参数,将Object转成Type类型的Object,返回Type类型的Object。
      下面类似的两个方法,不过方向相反,是从其他类型装换回来。
        CanConverterFrom 重载,
                 TypeConverter.CanConvertFrom (Type)
                 TypeConverter.CanConvertFrom (ITypeDescriptorContext, Type)
           在方法体里面判断参数Type是不是能转换回来的类型,例如string类型,如果是返回true,否则返回false。
        ConverterFrom 重载,
                TypeConverter.ConvertFrom (Object)
                TypeConverter.ConvertFrom (ITypeDescriptorContext, CultureInfo, Object)
           在方法体里面判断参数Object的类型是不是能转换回来的类型,例如string类型,如果是返回转换回来的类型。
          
        举例说明,以GPS经纬度位置为例,经纬度位置GPSLocation包括复杂属性经度Longitude和纬度Latitude。现我们根据其一属性Longitude类写个LongtitudeTypeConverter类。
        首先我们得有个Longtitude类吧。

    public class Longitude
    {
        
    private int _Degrees;
        
    private int _Minutes;
        
    private int _Seconds;
        
    private LongitudeDirection _Direction;

        
    /// <summary>
        
    /// 度数
        
    /// </summary>
        public int Degrees { }

        
    /// <summary>
        
    /// 分度
        
    /// </summary>
        public int Minutes { }

        
    /// <summary>
        
    /// 秒读
        
    /// </summary>
        public int Seconds { }

        
    /// <summary>
        
    /// 方向
        
    /// </summary>
        public LongitudeDirection Direction
        {
        }
    }

    有了个这个类,我们怎样将其转换到string类或其他类呢(这里假设string类)例如“24W3'4”形式,也许你会说重写ToString()方法不就行了,似乎可行,但如果转换成其他类呢,又从其他类转换回来呢,怎么办。还有在复杂控件中Designer设计中又该怎么办。(在复杂控件的应用稍后介绍)
        自然,这样我们是不是要写个转换类比较好呢,这个类必须直接或这间接继承TypeConverter类。


        
    class LongitudeTypeConverter : TypeConverter
        {
            
        }


    然后重载实现上面说的四个方法,现在我要Longitude类转换到string类型


    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
            {
                
    if (sourceType == typeof(string))
                    
    return true;
                
    else
                    
    return base.CanConvertFrom(context, sourceType);
            }

    public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
            {
                
    if ((destinationType == typeof(string)) |
                    (destinationType 
    == typeof(InstanceDescriptor)))
                    
    return true;
                
    else
                    
    return base.CanConvertTo(context, destinationType);
            }

    public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
            {
                
    // check that the value we got passed on is of type Longitude
                if (value != null)
                    
    if (!(value is Longitude))
                        
    throw new Exception(WrongType);

                
    // convert to a string
                if (destinationType == typeof(string))
                {
                    
    // no value so we return an empty string
                    if (value == null)
                        
    return string.Empty;

                    
    // strongly typed
                    Longitude LongValue = value as Longitude;

                    
    // get the two type converters to use
                    TypeConverter IntConverter = TypeDescriptor.GetConverter(typeof(int));
                    TypeConverter EnumConverter 
    = TypeDescriptor.GetConverter(typeof(LongitudeDirection));

                    
    // convert to a string and return
                    return IntConverter.ConvertToString(context, culture, LongValue.Degrees) +
                           EnumConverter.ConvertToString(context, culture, LongValue.Direction).Substring(
    01+
                           IntConverter.ConvertToString(context, culture, LongValue.Minutes) 
    + MinutesUnit +
                           IntConverter.ConvertToString(context, culture, LongValue.Seconds) 
    + SecondsUnit;
                }

                
    // convert to a instance descriptor
                if (destinationType == typeof(InstanceDescriptor))
                { 
                    
    // no value so we return no instance descriptor
                    if (value == null)
                        
    return null;

                    
    // strongly typed
                    Longitude LongValue = value as Longitude;

                    
    // used to descripe the constructor
                    MemberInfo Member = null;
                    
    object[] Arguments = null;

                    
    // get the constructor for the type
                    Member = typeof(Longitude).GetConstructor(new Type[] { typeof(int), typeof(int), typeof(int), typeof(LongitudeDirection) });

                    
    // create the arguments to pass along
                    Arguments = new object[] { LongValue.Degrees, LongValue.Minutes, LongValue.Seconds, LongValue.Direction };

                    
    // return the instance descriptor
                    if (Member != null)
                        
    return new InstanceDescriptor(Member, Arguments);
                    
    else
                        
    return null;
                }

                
    // call the base converter
                return base.ConvertTo(context, culture, value, destinationType);
            }

    public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
            {
                
    // no value so we return a new Longitude instance
                if (value == null)
                    
    return new Longitude();

                
    // convert from a string
                if (value is string)
                {
                    
    // get strongly typed value
                    string StringValue = value as string;

                    
    // empty string so we return a new Longitude instance
                    if (StringValue.Length <= 0)
                        
    return new Longitude();

                    
    // get the position of the West longitude separator
                    int DirectionPos = StringValue.IndexOf(LongitudeDirection.West.ToString().Substring(01));
                    LongitudeDirection Direction 
    = LongitudeDirection.West;

                    
    // if not found get the position of the East longitude separator
                    if (DirectionPos == -1)
                    {
                        DirectionPos 
    = StringValue.IndexOf(LongitudeDirection.East.ToString().Substring(01));
                        Direction 
    = LongitudeDirection.East;
                    }

                    
    // get the minutes and seconds characters
                    int MinutesPos = StringValue.IndexOf(MinutesUnit);
                    
    int SecondsPos = StringValue.IndexOf(SecondsUnit);

                    
    // no minutes present
                    if (MinutesPos == -1)
                        
    throw new Exception(MinutesMissing);

                    
    // no seconds present
                    if (SecondsPos == -1)
                        
    throw new Exception(SecondsMissing);

                    
    // no minutes present
                    if (DirectionPos == -1)
                        
    throw new Exception(DirectionMissing);

                    
    // no degrees present
                    if (DirectionPos == 0)
                        
    throw new Exception(DegreesMissing);

                    
    // get the type converters we need
                    TypeConverter IntConverter = TypeDescriptor.GetConverter(typeof(int));

                    
    // get the degrees, minutes and seconds value
                    int Degrees = (int)IntConverter.ConvertFromString(context, culture, StringValue.Substring(0, DirectionPos));
                    
    int Minutes = (int)IntConverter.ConvertFromString(context, culture, StringValue.Substring(DirectionPos + 1, MinutesPos - DirectionPos - 1));
                    
    int Seconds = (int)IntConverter.ConvertFromString(context, culture, StringValue.Substring(MinutesPos + 1, SecondsPos - MinutesPos - 1));

                    
    // create a new Longitude instance with these values and return it
                    return new Longitude(Degrees, Minutes, Seconds, Direction);
                }

                
    // otherwise call the base converter
                else
                    
    return base.ConvertFrom(context, culture, value);
            }


    有了这个转换类LongitudeTypeConverter,该怎么使用呢。其实很简单就是使用我们上面实现的四个方法,

     class Test
        {
            
    public static void Main(string[] args)
            {
                
    //将Longitude类转换到string类型
                Longitude longitude = new Longitude(10,11,12,LongitudeDirection.East);
                LongitudeTypeConverter converter 
    = new LongitudeTypeConverter();

                
    string strLongitude="";
                
    if (converter.CanConvertTo(typeof(string)))
                {
                    strLongitude 
    = (string)converter.ConvertTo(longitude, typeof(string));
                }
                System.Console.WriteLine(strLongitude);

                
    //将string还原回Longitude类
                Longitude longitude1 = new Longitude();
                
    if (converter.CanConvertFrom(typeof(string)))
                {
                    longitude1 
    = (Longitude)converter.ConvertFrom(strLongitude);
                }
                System.Console.WriteLine(longitude1.Degrees);
                System.Console.WriteLine(longitude1.Direction);
                System.Console.WriteLine(longitude1.Minutes);
                System.Console.WriteLine(longitude1.Seconds);
            }
        }

    输出结果是
    10E11'12''
    10
    East
    11
    12
    从结果中我们可以看到实现了我们预期的效果。
    这 些在一般代码里面可以用到,但从转换的结果中我们可以联想,web页面设计的两种模式(设计模式,源代码模式),在源代码模式我们显示的是string, 但在设计模式我们显示控件的外观,这里就关系到TypeConverter类了,当然还有TypeConverterAtrribute。
    下面就要说下这个TypeConverterAtrribute了。

    转载自 http://blog.csdn.net/luyifeiniu/article/details/5107832

  • 相关阅读:
    基本架构思想
    tensorflow|tf.train.slice_input_producer|tf.train.Coordinator|tf.train.start_queue_runners
    tfsenflow队列|tf.train.slice_input_producer|tf.train.Coordinator|tf.train.start_queue_runners
    tensorflow队列tf.FIFOQueue | enqueue | enqueue_many | dequeue | dequeue_many
    Tensorflow-gpu1.13.1 和 Tensorflow-gpu2.0.0共存之安装教程
    pandas相关操作
    Numpy的基本运算及操作
    Numpy基础之创建与属性
    Series序列
    os.walk|图片数据集
  • 原文地址:https://www.cnblogs.com/wsion/p/3030208.html
Copyright © 2020-2023  润新知