实现不可转换接口

本文关键字:接口 可转换 实现 | 更新日期: 2023-09-27 18:15:18

我有自定义类型LocalizedString,我需要实现IConvertible接口,因为当我们序列化类型到我们的DB时,我们使用Convert。更改类型,我不能更改这部分代码。

我所做的就是实现:

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 = "", pr.__property.PropertyType = {Name = "LocalizedString" FullName = "Sampo.CMS.LocalizedString"}代码崩溃:

从'System '强制转换无效。String' to 'Sampo.CMS.LocalizedString'.

我还需要做什么?

实现不可转换接口

如果你在看MSDN系统。在IConvertable的例子中,你会看到他们使用了Convert。在它们的实现中更改类型,但那是因为它们传递了要转换的double类型。转换。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个方法,你可能也可以为它们抛出invalidcastexception…

还有,你在IConvertable中使用string.Format(this.ToString())有什么原因吗?ToString实现吗?你没有传递任何参数,所以它不应该只是返回this.ToString()吗?


这里有一些可能有用的链接:

c# .NET中使用IConvertible接口的类型转换示例

系统。从某个版本转换源代码。它有Convert的源代码。所以你可以看看它到底在做什么以及为什么它不起作用

基于Brent Rittenhouse的答案的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 
            
        /*....*/
}