实现IConvertible接口

时间:2016-10-28 07:56:09

标签: c# .net

我有一个名为 LocalizedString 的自定义类型,我需要实现 IConvertible 接口,因为当我们将类型序列化到我们的数据库时,我们使用 Convert.ChangeType 我无法改变这部分代码。

我所做的是我实施了:

    string IConvertible.ToString(IFormatProvider provider)
    {
        return string.Format(this.ToString());
    }

    object IConvertible.ToType(Type conversionType, IFormatProvider provider)
    {
        return Convert.ChangeType(this.ToString(), conversionType);
    }

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

我用 NotImplementedException 留下了所有其他方法,因为我没有任何合理的转换到其他类型。 (我最终会让他们抛出 InvalidCastException ,但那是另一个故事。)

但是,当我调用Convert.ChangeType(val, pr.__property.PropertyType)val = ""代码崩溃时,我仍然会收到:

  

来自' System.String'的无效演员表到' Sampo.CMS.LocalizedString'。

我还需要做些什么?我被卡住了。

2 个答案:

答案 0 :(得分:1)

如果您正在查看MSDN System.IConvertable example,您会看到他们在实现中使用了Convert.ChangeType,但那是因为他们传入了一个要转换的double。 Convert.ChangeType不会知道如何转换为自定义对象类型或从自定义对象类型转换。我很确定你需要在其中实现转换,例如:

object IConvertible.ToType(Type conversionType, IFormatProvider provider)
{
    if (conversionType == typeof(Sampo.CMS.LocalizedString))
    {
        // Do your conversion here and return the string.
        return this.ToString() + "!!!!";
    }

    throw new InvalidCastException($"Converting type \"{typeof(LocalizedString )}\" to type \"{conversionType.Name}\" is not supported.");
}

实际上,对于你必须实现的16个左右方法的其余部分,你可能只是为它们抛出InvalidCastExceptions ...

另外,您是否有理由在IConvertable.ToString实现中执行string.Format(this.ToString())?你没有传递任何参数,所以不应该只是返回this.ToString()?

以下是一些可能有用的链接:

Type conversion example in C# .NET using the IConvertible interface

某些版本的

System.Convert source。它具有Convert.ChangeType的源代码,因此您可以查看它实际在做什么以及为什么它不起作用。

答案 1 :(得分:0)

基于 Brent Rittenhouse's 答案的 IConvertible 的完整实现。

public struct TableAddress : IConvertible 
{
        /*....*/
    
        #region IConvertible Implementation
        static T ThrowNotSupported<T>()
        {
            var ex = ThrowNotSupported(typeof(T));
            return (T)ex;
        }

        static object ThrowNotSupported(Type type)
        {
            throw new InvalidCastException($"Converting type \"{typeof(TableAddress)}\" to type \"{type}\" is not supported.");
        }

        TypeCode IConvertible.GetTypeCode()
        {
            return TypeCode.Object;
        }

        bool IConvertible.ToBoolean(IFormatProvider provider) => ThrowNotSupported<bool>();
        char IConvertible.ToChar(IFormatProvider provider) => ThrowNotSupported<char>();
        sbyte IConvertible.ToSByte(IFormatProvider provider) => ThrowNotSupported<sbyte>();
        byte IConvertible.ToByte(IFormatProvider provider) => ThrowNotSupported<byte>();
        short IConvertible.ToInt16(IFormatProvider provider) => ThrowNotSupported<short>();
        ushort IConvertible.ToUInt16(IFormatProvider provider) => ThrowNotSupported<ushort>();
        int IConvertible.ToInt32(IFormatProvider provider) => ThrowNotSupported<int>();
        uint IConvertible.ToUInt32(IFormatProvider provider) => ThrowNotSupported<uint>();
        long IConvertible.ToInt64(IFormatProvider provider) => ThrowNotSupported<long>();
        ulong IConvertible.ToUInt64(IFormatProvider provider) => ThrowNotSupported<ulong>();
        float IConvertible.ToSingle(IFormatProvider provider) => ThrowNotSupported<float>();
        double IConvertible.ToDouble(IFormatProvider provider) => ThrowNotSupported<double>();
        decimal IConvertible.ToDecimal(IFormatProvider provider) => ThrowNotSupported<decimal>();
        DateTime IConvertible.ToDateTime(IFormatProvider provider) => ThrowNotSupported<DateTime>();
        string IConvertible.ToString(IFormatProvider provider) => ThrowNotSupported<string>();

        object IConvertible.ToType(Type conversionType, IFormatProvider provider)
        {
            if (conversionType == typeof(TableAddress))
            {
                return this;
            }
            
            // Other implementations here

            return ThrowNotSupported(conversionType);
        }
        #endregion 
            
        /*....*/
}