Saturday, May 17, 2008

For the last time

Every now and then I have to create a type converter (System.ComponentModel.TypeConverter), often to convert custom types to and from strings, there is some repetitive work involved in this. You have to override the CanConvertFrom- and CanConvertTo-methods and implement the conversion, now I've done this repetitive work for the last time since I created a class I call TypeConverterBase<TSource, TDestination> which implements all the logic save the conversion which it has two abstract methods for, it also has an abstract method IsValid for the destination type of the converter. It also provides some typed overloads for ConvertTo and ConvertFrom.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;

namespace Minimal
{
    /// <summary>
    /// Provides the base implementation for a type converter that converts between
    /// two types, only the abstract methods has to be implemented for a fully working
    /// type converter.
    /// </summary>
    /// <typeparam name="TSource">The source type of the converter.</typeparam>
    /// <typeparam name="TDestination">The destination type of the converter.</typeparam>
    public abstract class TypeConverterBase<tsource  , tdestination>
        : TypeConverter
    {
        #region Methods
        /// <summary>
        /// Gets whether the converter can convert from the source type to
        /// the type specified.
        /// </summary>
        /// <param name="context" />The context of the converter.</param>
        /// <param name="destinationType" />The type to check.</param>
        /// <returns>True if a conversion can be made.</returns>
        public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
        {
            if (destinationType.Equals(typeof(TDestination)))
            {
                return true;
            }

            return base.CanConvertTo(context, destinationType);
        }

        /// <summary>
        /// Gets whether the converter can convert to the source type of the converter to
        /// the type specified.
        /// </summary>
        /// <param name="context" />The context of the converter.</param>
        /// <param name="sourceType" />The type to check.</param>
        /// <returns>True if a conversion can be made.</returns>
        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
        {
            if (sourceType.Equals(typeof(TDestination)))
            {
                return true;
            }

            return base.CanConvertFrom(context, sourceType);
        }

        /// <summary>
        /// Converts from the source type to the destination type.
        /// </summary>
        /// <param name="value" />The value to convert.</param>
        /// <returns>The converted value.</returns>
        public TDestination ConvertTo(TSource value)
        {
            return (TDestination)this.ConvertTo(value, typeof(TDestination));
        }

        /// <summary>
        /// Converts to the source type of the converter from the destination type.
        /// </summary>
        /// <param name="value" />The value to convert.</param>
        /// <returns>The converted value.</returns>
        public TSource ConvertFrom(TDestination value)
        {
            return (TSource)base.ConvertFrom(value);
        }

        ///<summary>
        /// Converts the given object to the type of this converter, using the specified
        /// context and culture information.
        /// </summary>
        /// <param name="context" />An System.ComponentModel.ITypeDescriptorContext that provides a format context.</param>
        /// <param name="culture" />The System.Globalization.CultureInfo to use as the current culture.</param>
        /// <param name="value" />The System.Object to convert.</param>
        /// <returns>An System.Object that represents the converted value.</returns>
        /// <exception cref="NotSupportedException">The conversion cannot be performed.</exception>
        public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
        {
            if (value is TDestination)
            {
                return this.ConvertFrom(context, culture, (TDestination)value);
            }
            
            return base.ConvertFrom(context, culture, value);
        }

        /// <summary>
        /// Converts the given value object to the specified type, using the specified
        /// context and culture information.
        /// </summary>
        /// <param name="context" />An System.ComponentModel.ITypeDescriptorContext that provides a format context.</param>
        /// <param name="culture" />A System.Globalization.CultureInfo. If null is passed, the current culture
        /// is assumed.</param>
        /// <param name="value" />The value to convert.</param>
        /// <param name="destinationType" />The System.Type to convert the value parameter to.</param>
        /// <returns>An System.Object that represents the converted value.</returns>
        /// <exception cref="ArgumentNullException">System.ArgumentNullException: The destinationType parameter is null.</exception>
        /// <exception cref="NotSupportedException">The conversion cannot be performed.</exception>
        public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
        {
            if (destinationType.Equals(typeof(TDestination)))
            {
                return this.ConvertTo(context, culture, (TSource)value);
            }

            return base.ConvertTo(context, culture, value, destinationType);
        }

        /// <summary>
        /// Returns whether the given value object is valid for this type and for the
        /// specified context.
        /// </summary>
        /// <param name="context" />An System.ComponentModel.ITypeDescriptorContext that provides a format context.</param>
        /// <param name="value" />The System.Object to test for validity.</param>
        /// <returns> true if the specified value is valid for this object; otherwise, false.</returns>
        public override bool IsValid(ITypeDescriptorContext context, object value)
        {
            if (value is TDestination)
            {
                return this.IsValid(context, (TDestination)value);
            }

            return base.IsValid(context, value);
        }

        protected abstract TSource ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, TDestination value);
        protected abstract TDestination ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, TSource value);
        protected abstract bool IsValid(ITypeDescriptorContext context, TDestination value);
        #endregion
    }
}