【发布时间】:2021-03-06 10:05:47
【问题描述】:
我有一个自定义类型:
[TypeConverter(typeof(FriendlyUrlTypeConverter))]
public class FriendlyUrl : IEquatable<FriendlyUrl>, IConvertible
{
public FriendlyUrl()
{
_friendlyUrl = string.Empty;
}
public FriendlyUrl(string value)
{
value = value.Trim();
if (!FriednlyUrlValidator.Validate(value))
throw new FriendlyUrlValidationException("Invalid value for FrienlyUrl");
_friendlyUrl = value;
}
public static implicit operator FriendlyUrl(string friendlyUrlValue)
{
if (friendlyUrlValue != "" && !FriednlyUrlValidator.Validate(friendlyUrlValue))
throw new FriendlyUrlValidationException($"Invalid value for FrienlyUrl: {friendlyUrlValue}");
return new FriendlyUrl { _friendlyUrl = friendlyUrlValue };
}
public static implicit operator string(FriendlyUrl furl)
{
return furl._friendlyUrl;
}
public override string ToString()
{
return _friendlyUrl;
}
private string _friendlyUrl;
//[...skip IEquatable implementation...]
TypeCode IConvertible.GetTypeCode()
{
return _friendlyUrl.GetTypeCode();
}
bool IConvertible.ToBoolean(IFormatProvider provider)
{
return ((IConvertible) _friendlyUrl).ToBoolean(provider);
}
byte IConvertible.ToByte(IFormatProvider provider)
{
return ((IConvertible) _friendlyUrl).ToByte(provider);
}
char IConvertible.ToChar(IFormatProvider provider)
{
return ((IConvertible) _friendlyUrl).ToChar(provider);
}
DateTime IConvertible.ToDateTime(IFormatProvider provider)
{
return ((IConvertible) _friendlyUrl).ToDateTime(provider);
}
decimal IConvertible.ToDecimal(IFormatProvider provider)
{
return ((IConvertible) _friendlyUrl).ToDecimal(provider);
}
double IConvertible.ToDouble(IFormatProvider provider)
{
return ((IConvertible) _friendlyUrl).ToDouble(provider);
}
short IConvertible.ToInt16(IFormatProvider provider)
{
return ((IConvertible) _friendlyUrl).ToInt16(provider);
}
int IConvertible.ToInt32(IFormatProvider provider)
{
return ((IConvertible) _friendlyUrl).ToInt32(provider);
}
long IConvertible.ToInt64(IFormatProvider provider)
{
return ((IConvertible) _friendlyUrl).ToInt64(provider);
}
sbyte IConvertible.ToSByte(IFormatProvider provider)
{
return ((IConvertible) _friendlyUrl).ToSByte(provider);
}
float IConvertible.ToSingle(IFormatProvider provider)
{
return ((IConvertible) _friendlyUrl).ToSingle(provider);
}
string IConvertible.ToString(IFormatProvider provider)
{
return _friendlyUrl.ToString(provider);
}
object IConvertible.ToType(Type conversionType, IFormatProvider provider)
{
if (conversionType == typeof(FriendlyUrl))
return this;
return ((IConvertible) _friendlyUrl).ToType(conversionType, provider);
}
ushort IConvertible.ToUInt16(IFormatProvider provider)
{
return ((IConvertible) _friendlyUrl).ToUInt16(provider);
}
uint IConvertible.ToUInt32(IFormatProvider provider)
{
return ((IConvertible) _friendlyUrl).ToUInt32(provider);
}
ulong IConvertible.ToUInt64(IFormatProvider provider)
{
return ((IConvertible) _friendlyUrl).ToUInt64(provider);
}
}
这里是 Json 序列化/反序列化 (xUnit) 的测试:
[Fact]
public void ConvertToJsonAndBack()
{
FriendlyUrl friendlyUrl = "some-friendly-url-1";
string friendlyUrlJson = JsonConvert.SerializeObject(friendlyUrl);
Assert.Equal($"\"{friendlyUrl}\"", friendlyUrlJson);
// ******** Throws the next line: ********
FriendlyUrl deserialized = JsonConvert.DeserializeObject<FriendlyUrl>(friendlyUrlJson);
Assert.Equal(friendlyUrl, deserialized);
}
抛出异常:
Newtonsoft.Json.JsonSerializationException:将值“some-friendly-url-1”转换为类型“BlahBlah.Entities.FriendlyUrl”时出错。路径'',第 1 行,位置 21。 ---- System.InvalidCastException : 从“System.String”到“BlahBlah.Entities.FriendlyUrl”的无效转换。
堆栈跟踪:
堆栈跟踪: JsonSerializerInternalReader.EnsureType(JsonReader reader, Object value, CultureInfoculture, JsonContract contract, Type targetType) JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue) JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent) JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType) JsonSerializer.Deserialize(JsonReader reader, Type objectType) JsonConvert.DeserializeObject(字符串值,类型类型,JsonSerializerSettings 设置) JsonConvert.DeserializeObject[T](字符串值,JsonSerializerSettings 设置) JsonConvert.DeserializeObject[T](字符串值)
现在,如果我删除 IConvertible 实现并只留下它确实工作:
- 显式和隐式 'FriendlyUrl 字符串' 转换运算符。
-
TypeConverter实现 - 见第一行。
但是当类实现IConvertible 时,我得到了那个错误。我该如何解决这个问题?
(我真的需要IConvertible 来实现。我也尝试使用JsonObject,但没有帮助)。
小提琴
这是重现 - https://dotnetfiddle.net/YPfr60。
类型转换器
public class FriendlyUrlTypeConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
return value is string sValue ? new FriendlyUrl(sValue) : base.ConvertFrom(context, culture, value);
}
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
return destinationType == typeof(string) ? value.ToString() : base.ConvertTo(context, culture, value, destinationType);
}
}
【问题讨论】: