IConvertible Interface

Overview

  • Enables a class to be converted to a base type such as Boolean, Byte, Double, or String.
  • C# allows widening conversion without any casting, e.g.: going from int to double, see below.
  • Narrowing conversion requires explicit conversion.
  • Overloading operators allows for implicit and explicit conversion of custom types, as demonstrated below.
  • Implementing IConvertible allows the use of Convert with your custom type.

Examples

Widening conversion

int i = 1;
double d = 1.0001;
d = i; // Compiles without casting.

Narrowing Conversion

Int16 a = 1;
Int32 b = 1;
double c = 1;
 
a = (Int16)b; // a = b will not be allowed, narrowing!
a = (Int16)c; // a = c will not be allowed, narrowing!
 
b = a;        // Allowed, widening
b = (Int32)c; // b = c will not be allowed, narrowing!
 
c = a;        // Allowed, widening
c = b;        // Allowed, widening

Overloading Operators

class Program
{
    static void Main(string[] args)
    {
        MyPlaceholder a ;
        int b;
 
        // Allowed because of the 'implicit' operator
        a = 5;
        Console.WriteLine(a.Value);
 
        // Allowed because of the string implicit operator,
        // don't do this however!! Way to error-prone!
        a = "7";
        Console.WriteLine(a.Value);
 
        // Allowed because of the 'explicit' operator
        b = (int)a;
        Console.WriteLine(b);
    }
}
 
public class MyPlaceholder
{
    public int Value { get; private set; }
 
    public MyPlaceholder(int value)
    {
        Value = value;
    }
 
    public static implicit operator MyPlaceholder(int arg)
    {
        MyPlaceholder obj = new MyPlaceholder(arg);
        return obj;
    }
 
    public static implicit operator MyPlaceholder(string arg)
    {
        MyPlaceholder obj = new MyPlaceholder(Convert.ToInt32(arg));
        return obj;
    }
 
    public static explicit operator int(MyPlaceholder arg)
    {
        return arg.Value;
    }
}

Implementing IConvertible

class Program
{
    static void Main(string[] args)
    {
        MyPlaceholder a = new MyPlaceholder(5);
        int b;
 
        // Allowed because of the IConvertible interface
        b = Convert.ToInt32(a);
        Console.WriteLine(b);
 
        // Allowed because of the IConvertible interface
        Console.WriteLine(Convert.ToDouble(a));
 
        // Not Allowed because of the InvalidCastException
        Console.WriteLine(Convert.ToDateTime(a));
    }
}
 
public class MyPlaceholder: IConvertible
{
    public int Value { get; private set; }
 
    public MyPlaceholder(int value)
    {
        Value = value;
    }
 
    #region IConvertible Members
    public double ToDouble(IFormatProvider provider) { return Value; }
    public float ToSingle(IFormatProvider provider) { return Value; }
    public int ToInt32(IFormatProvider provider) { return Value; }
    public long ToInt64(IFormatProvider provider) { return Value; }
    public string ToString(IFormatProvider provider) { return Value.ToString(); }
 
    public TypeCode GetTypeCode()
    {
        return TypeCode.Object;
    }
 
    public bool ToBoolean(IFormatProvider provider)
    {
        throw new InvalidCastException();
    }
 
    public byte ToByte(IFormatProvider provider)
    {
        throw new InvalidCastException();
    }
 
    public char ToChar(IFormatProvider provider)
    {
        throw new InvalidCastException();
    }
 
    public DateTime ToDateTime(IFormatProvider provider)
    {
        throw new InvalidCastException();
    }
 
    public decimal ToDecimal(IFormatProvider provider)
    {
        throw new InvalidCastException();
    }
 
    public short ToInt16(IFormatProvider provider)
    {
        throw new InvalidCastException();
    }
 
    public sbyte ToSByte(IFormatProvider provider)
    {
        throw new InvalidCastException();
    }
 
    public object ToType(Type conversionType, IFormatProvider provider)
    {
        throw new InvalidCastException();
    }
 
    public ushort ToUInt16(IFormatProvider provider)
    {
        throw new InvalidCastException();
    }
 
    public uint ToUInt32(IFormatProvider provider)
    {
        throw new InvalidCastException();
    }
 
    public ulong ToUInt64(IFormatProvider provider)
    {
        throw new InvalidCastException();
    }
    #endregion
}