我有一个名为 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'。
我还需要做些什么?我被卡住了。
答案 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
/*....*/
}