Sanırım işlevin neden çalışmadığını açıklamalıyım:
1- İstisnayı veren satır aşağıdaki gibidir:
throw new InvalidCastException(Environment.GetResourceString("InvalidCast_FromTo", new object[]
{
value.GetType().FullName,
targetType.FullName
}));
aslında Convert.ConvertTypes dizisindeki işlev arama bundan sonra targer'ın bir Enum olup olmadığını görür ve hiçbir şey bulunamadığında yukarıdaki istisnayı atar.
2- Convert.ConvertTypes şu şekilde başlatılır:
Convert.ConvertTypes = new RuntimeType[]
{
(RuntimeType)typeof(Empty),
(RuntimeType)typeof(object),
(RuntimeType)typeof(DBNull),
(RuntimeType)typeof(bool),
(RuntimeType)typeof(char),
(RuntimeType)typeof(sbyte),
(RuntimeType)typeof(byte),
(RuntimeType)typeof(short),
(RuntimeType)typeof(ushort),
(RuntimeType)typeof(int),
(RuntimeType)typeof(uint),
(RuntimeType)typeof(long),
(RuntimeType)typeof(ulong),
(RuntimeType)typeof(float),
(RuntimeType)typeof(double),
(RuntimeType)typeof(decimal),
(RuntimeType)typeof(DateTime),
(RuntimeType)typeof(object),
(RuntimeType)typeof(string)
};
Dolayısıyla int?
, ConvertTypes dizisinde olmadığından ve Enum olmadığından, istisna atılır.
Devam etmek için, Convert.ChnageType işlevinin çalışması için elinizde:
Dönüştürülecek nesne IConvertible
Hedef türü ConvertTypes içinde ve Empty
ne de değil DBNull
(Atma istisnası olan bu ikisinde açık bir test var)
Bu davranışın nedeni int
(ve diğer tüm varsayılan türlerin) Convert.DefaultToType
IConvertibale olarak kullanılmasıdır.ToType implementation. and here is the code of the
DefaultToType extracted
usingILSpy
internal static object DefaultToType(IConvertible value, Type targetType, IFormatProvider provider)
{
if (targetType == null)
{
throw new ArgumentNullException("targetType");
}
RuntimeType left = targetType as RuntimeType;
if (left != null)
{
if (value.GetType() == targetType)
{
return value;
}
if (left == Convert.ConvertTypes[3])
{
return value.ToBoolean(provider);
}
if (left == Convert.ConvertTypes[4])
{
return value.ToChar(provider);
}
if (left == Convert.ConvertTypes[5])
{
return value.ToSByte(provider);
}
if (left == Convert.ConvertTypes[6])
{
return value.ToByte(provider);
}
if (left == Convert.ConvertTypes[7])
{
return value.ToInt16(provider);
}
if (left == Convert.ConvertTypes[8])
{
return value.ToUInt16(provider);
}
if (left == Convert.ConvertTypes[9])
{
return value.ToInt32(provider);
}
if (left == Convert.ConvertTypes[10])
{
return value.ToUInt32(provider);
}
if (left == Convert.ConvertTypes[11])
{
return value.ToInt64(provider);
}
if (left == Convert.ConvertTypes[12])
{
return value.ToUInt64(provider);
}
if (left == Convert.ConvertTypes[13])
{
return value.ToSingle(provider);
}
if (left == Convert.ConvertTypes[14])
{
return value.ToDouble(provider);
}
if (left == Convert.ConvertTypes[15])
{
return value.ToDecimal(provider);
}
if (left == Convert.ConvertTypes[16])
{
return value.ToDateTime(provider);
}
if (left == Convert.ConvertTypes[18])
{
return value.ToString(provider);
}
if (left == Convert.ConvertTypes[1])
{
return value;
}
if (left == Convert.EnumType)
{
return (Enum)value;
}
if (left == Convert.ConvertTypes[2])
{
throw new InvalidCastException(Environment.GetResourceString("InvalidCast_DBNull"));
}
if (left == Convert.ConvertTypes[0])
{
throw new InvalidCastException(Environment.GetResourceString("InvalidCast_Empty"));
}
}
throw new InvalidCastException(Environment.GetResourceString("InvalidCast_FromTo", new object[]
{
value.GetType().FullName,
targetType.FullName
}));
}
diğer yandan, cast Nullable sınıfının kendisi tarafından gerçekleştirilir ve tanım şu şekildedir:
public static implicit operator T?(T value)
{
return new T?(value);
}
public static explicit operator T(T? value)
{
return value.Value;
}
Nullable<T>
uygulamıyorIConvertible