我需要一个TypeConverter,理想情况下,将String转换为类型安全枚举类(CountryIso),而不必为我即将制作的每个类型安全枚举编写转换器。
虽然我设法让以下工作:
CountryIso cI = (CountryIso) "1";
我无法让它与泛型一起工作!以下示例不起作用,但为什么?
TypeDescriptor.AddProvider(new ExplicitCastDescriptionProvider<CountryIso>(), typeof(CountryIso));
var descriptor = TypeDescriptor.GetConverter(typeof(CountryIso));
var result = descriptor.ConvertFrom("1");
我目前有一个通用的TypeConverter实现:
public class ExplicitCastConverter<T>: TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
// Always true: the type determines if a cast is available or not
return true;
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
String dummy = (String) value;
//CountryIso tst = (CountryIso) value; // Allowed, no problem casting
//CountryIso tst = (CountryIso) dummy; // Allowed, no problem casting
//var dum_001 = (T) ((String) value); // Does not compile
//var dumdum = (T) value; // Invalid case exception
//var hoot = (T) Convert.ChangeType(value, typeof (T)); // Invalid cast exception
return null;
}
}
提供者如下:
//thanks: http://groups.google.com/group/wpf-disciples/browse_thread/thread/9f7bb40b7413fcd
public class ExplicitCastDescriptionProvider<T> : TypeDescriptionProvider //where T:TypeSafeEnum
{
public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
{
return new ImplicitCastDescription<T>();
}
}
public class ImplicitCastDescription<T>: CustomTypeDescriptor //where T:TypeSafeEnum
{
public override TypeConverter GetConverter()
{
return new ExplicitCastConverter<T>();
}
}
我有一个类型安全的枚举实现CountryIso(感谢StackOverflow!):
public sealed class CountryIso: TypeSafeEnum
{
private static readonly Dictionary<int, CountryIso> InstanceDict = new Dictionary<int, CountryIso>();
public static readonly CountryIso NL = new CountryIso(1, "NL", "Netherlands");
public static readonly CountryIso BE = new CountryIso(2, "BE", "Belgium");
private CountryIso(int value, String name, String description): base(value,name,description)
{
InstanceDict.Add(value, this);
}
public static Dictionary<int, CountryIso> Instances
{
get { return new Dictionary<int, CountryIso>(InstanceDict); }
}
public static explicit operator CountryIso(String i)
{
int index;
return Int32.TryParse(i,out index) ? InstanceDict[index] : null;
}
}
继承自TypeSafeEnum:
public class TypeSafeEnum
{
protected TypeSafeEnum(int value, String name, String description)
{
Name = name;
Value = value;
Description = description;
}
public int Value{ get; private set; }
public String Name { get; private set; }
public String Description { get; private set; }
}
答案 0 :(得分:0)
一个选项:使用反射
问题在于CountryIso成员的静态特性以及(主要是)转换运算符。这可以防止任何蓝图定义使通用的类型转换器知道它可以转换CountryIso类型的安全枚举。此外,您无法强制转换'down':TypeSafeEnum永远不会成为CountryIso。这是合乎逻辑的,但没有帮助。
[使用反射]
引入了定义转换方法的通用接口:
public interface ICast<out T>
{
T Cast(String obj);
}
将接口应用于CountryIso
public sealed class CountryIso: TypeSafeEnum , ICast<CountryIso>
将接口作为contstraint添加到转换器类
public class ExplicitCastConverter<T>: TypeConverter where T: ICast<T>
向CountryIso添加(非静态)强制转换方法:
public new CountryIso Cast(String obj)
{
int index;
return Int32.TryParse(obj, out index) ? InstanceDict[index] : null;
}
在我的type-safe-enum中添加了一个默认的静态成员:
private static readonly CountryIso DefaultTypeSafeEnum = new CountryIso(
-1,
null,
null
);
在Converter类中实现ConvertFrom(..):
T defaultMember = (T)typeof(T).GetField(
"DefaultTypeSafeEnum",
BindingFlags.NonPublic | BindingFlags.Static
).GetValue(null);
return defaultMember.Cast((String) value);
[类型安全枚举安全]
仍然可以创建&amp;通过反射插入CountryIso的新实例(特别是在使用InstanceDict进行实例访问时!)一些示例代码:
ConstructorInfo ci = typeof (T).GetConstructor(
BindingFlags.NonPublic|BindingFlags.Instance,
null,
CallingConventions.Standard,
new [] {typeof (int), typeof (String), typeof (String)},
new ParameterModifier[0]
);
CountryIso countryIso = (CountryIso) ci.Invoke(new object[]{30, "ZB", "Zanzibar"});
我现在考虑使用私有InstanceDict成员安全漏洞(不是很大,因为我不是为外界编程API,但仍然......)