假设我有以下愿望,简化IConvertible,允许我使用泛型类型参数调用它们。我计划通过创建通用转换器并将它们存储在静态通用类的静态属性中来实现这一点。下面是生成委托的代码:
static class IConvertibleHelper<T> where T : struct, IConvertible
{
public static readonly Converter<IConvertible, T> Converter;
public static readonly Converter<IConvertible, T?> NullableConverter;
static IConvertibleHelper()
{
Type type = typeof(T).IsEnum ? Enum.GetUnderlyingType(typeof(T)) : typeof(T);
Converter = Delegate.CreateDelegate(typeof(Converter<IConvertible, T>), typeof(Convert).GetMethod("To" + type.Name,new Type[]{typeof(object)})) as Converter<IConvertible, T>;
NullableConverter = obj => obj == null ? default(T?) : (T?)Converter(obj);
}
}
顺便说一句,添加对枚举的支持有一个小的副作用,因为它们继承自IConvertible,而且显然,从UnderyLingType到Enum的转换是隐式的,因此只需要委托的返回类型。
现在,完成了最难的部分,我想添加扩展方法:
public static class IConvertibleHelper
{
public static T To<T>(this IConvertible convertible) where T:struct,IConvertible
{
return IConvertibleHelper<T>.Converter(convertible);
}
public static T? To<T?>(this IConvertible convertible) where T : struct, IConvertible
{
return IConvertibleHelper<T>.NullableConverter(convertible);
}
}
第一种扩展方法是好的,甚至可以工作!
第二个扩展根本无法编译。我可以使用以下相当蹩脚的工作:
public static T? ToNullable<T>(this IConvertible convertible) where T : struct, IConvertible
{
return IConvertibleHelper<T>.NullableConverter(convertible);
}
但是我们仍然需要调用一个不同的签名来转换为可以为空的值类型。
更糟糕的解决方法(出于可用性原因,imo)是使用out或ref参数返回,并正确使用两种方法。这在技术上允许出现类型推理的魔力,但使调用这个简单的小扩展方法更加烦人。