Search code examples
.netgenericsstructcastingiconvertible

Cast from int to custom struct C#


I am writing a custom generic VectorN class, where T: struct, IFormattable, IComparable, IConvertible. I can access an indexed value of vector by this[int index]. So in a loop I do this piece of code to make VectorN.One:

r[i] = (T)Convert.ChangeType(1, typeof(T));

It works perfectly with standard numbers such as int, decimal, etc., however when I wrote a custom struct uHalfByte for testing, it gives an error:

Invalid cast from 'System.Int32' to 'uHalfByte'.

Here is the script of uHalfByte:

struct uHalfByte : IFormattable, IComparable<uHalfByte>, IConvertible
{
    private byte val;
    public byte Val
    {
        get { return (byte)(val & 0xF); }
        set { val = (byte)(value & 0xF); }
    }
    public uHalfByte(byte val)
    {
        this.val = (byte)(val & 0xF);
    }

    public string ToString(string format, IFormatProvider formatProvider)
    {
        if (formatProvider == null) formatProvider = System.Globalization.CultureInfo.CurrentCulture;
        if (string.IsNullOrEmpty(format)) format = "G";
        string s = "";
        for (int i = 0; i < 4; i++) s += ((Val >> i) & 1).ToString(format,formatProvider);
        return s;
    }

    public int CompareTo(uHalfByte other)
    {
        return this.Val - other.Val;
    }

    public TypeCode GetTypeCode()
    {
        return TypeCode.Byte;
    }

    public bool ToBoolean(IFormatProvider provider)
    {
        return val!=0;
    }

    public char ToChar(IFormatProvider provider)
    {
        return (char)val;
    }

    public sbyte ToSByte(IFormatProvider provider)
    {
        return (sbyte)val;
    }

    public byte ToByte(IFormatProvider provider)
    {
        return (byte)val;
    }

    public short ToInt16(IFormatProvider provider)
    {
        return (short)val;
    }

    public ushort ToUInt16(IFormatProvider provider)
    {
        return (ushort)val;
    }

    public int ToInt32(IFormatProvider provider)
    {
        return (int)val;
    }

    public uint ToUInt32(IFormatProvider provider)
    {
        return (uint)val;
    }

    public long ToInt64(IFormatProvider provider)
    {
        return (long)val;
    }

    public ulong ToUInt64(IFormatProvider provider)
    {
        return (ulong)val;
    }

    public float ToSingle(IFormatProvider provider)
    {
        return (float)val;
    }

    public double ToDouble(IFormatProvider provider)
    {
        return (double)val;
    }

    public decimal ToDecimal(IFormatProvider provider)
    {
        return (decimal)val;
    }

    public DateTime ToDateTime(IFormatProvider provider)
    {
        return new DateTime(val);
    }

    public string ToString(IFormatProvider provider)
    {
        return ToString("", provider);
    }

    public object ToType(Type conversionType, IFormatProvider provider)
    {
        return Convert.ChangeType(val, conversionType);
    }

    public static explicit operator uHalfByte(int val)
    {
        return new uHalfByte((byte)val);
    }
}

Did I do something wrong in uHalfByte or it is just impossible?


Solution

  • It won't work in that way, because System.Int32 (as stated in exception message) have no information about your custom class uHalfByte and can't perform that conversion. Of course it will work it other way uHalfByte -> int

    Edit:
    In your case I think you can use conversion operators: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/using-conversion-operators

    like this:

    struct uHalfByte
    {
        public static explicit operator uHalfByte(int value)
        {
            return new uHalfByte();
        }
        public static explicit operator uHalfByte(string value)
        {
            return new uHalfByte();
        }
    }
    

    usage:

    if (typeof(T) == typeof(uHalfByte)) 
        r[i] = (uHalfByte)value;
    else
        r[i] = (T)Convert.ChangeType(value, typeof(T));