我想上课TypeConverter
。这个课应该这样做:
1)它应该允许注册指定类型的转换(int到我的例子中的字符串)。
myClass.RegisterType<int> ((myIntValue) => (myIntValue + 1).ToString());
2)还应该有一种方法可以轻松转换:
string x = (string) myClass.Convert (5); // should return string "6"
在我不工作的实现中,我使用:Dictionary <Type, Func<object>> map;
来存储我的转换器。寄存器功能看起来像这样:
public void Register<TIn, TOut> (Converter<TIn, TOut> converter)
{
map.Add (typeof (TIn), () => converter);
}
现在我有一个问题就是编写一个转换对象的方法
public object Convert (object o)
{
// ... i can receive method from dictionary but i cannot execute it
// because it is object, so var converter = map[o.GetType] ();
// return converter (o); // will not work because i need to cast it
// but it is generic :/
}
答案 0 :(得分:2)
假设您有理由建立自己的自定义类型转换器,可以采用以下方法:
用法:
TypeConverter converter = new TypeConverter();
converter.Register<int, string>((a) => a == 3 ? "three!" : a.ToString());
converter.Register<int, int>((a) => 3);
string resultAsString = converter.Convert<string>(3); // returns "three!"
int resultAsInt = converter.Convert<int>(4); // returns 3
键入转换,调用委托,并将结果转换为目标类型。
public class TypeConverter
{
private Dictionary<KeyValuePair<Type, Type>, Delegate> _map = new Dictionary<KeyValuePair<Type, Type>, Delegate>();
public void Register<TIn, TOut>(Converter<TIn, TOut> converter)
{
_map.Add(new KeyValuePair<Type,Type>(typeof(TIn),typeof(TOut)), converter);
}
public T Convert<T>(object o)
{
Type inputType = o.GetType();
Delegate converter = null;
KeyValuePair<Type, Type> mapKey = new KeyValuePair<Type, Type>(inputType, typeof(T));
if (_map.TryGetValue(mapKey, out converter))
return (T)converter.Method.Invoke(null, new object[] { o });
throw new NotSupportedException(String.Format("No converter available for {0} to {1}", o.GetType().Name, typeof(T).Name));
}
}
答案 1 :(得分:1)
我在如何以非通用方式使用泛型类方面有类似的学习曲线,在我进行简单点击之前我无法弄清楚:使用接口。因此,如果您想以非通用方式使用通用转换器,请定义非通用接口并实现它。除非您执行检查以处理它,否则您将失去任何类型的安全性。
因此,在您的情况下,定义一个非通用接口。
private interface IConvertor {
object Convert(object obj);
}
在包装lambda的通用转换器类中实现它。
private class Convertor<TIn, TOut> : IConvertor {
public Convertor(Func<TIn, TOut> conversion) {
_conversion = conversion;
}
private readonly Func<TIn, TOut> _conversion;
object IConvertor.Convert(object obj) {
if (obj is TIn) {
return _conversion((TIn)obj);
}
throw new NotSupportedException();
}
}
现在将该类的实例存储在TypeConvertor
类中。
public class TypeConvertor {
private readonly Dictionary<Type, IConvertor> _convertors =
new Dictionary<Type, IConvertor>();
public void Register<TIn, TOut>(Func<TIn, TOut> conversion) {
_convertors.Add(typeof(TIn), new Convertor<TIn, TOut>(conversion));
}
public object Convert(object obj) {
if (obj == null)
throw new ArgumentNullException("obj");
return _convertors[obj.GetType()].Convert(obj);
}
}
简单易懂。当然,你已经通过存储Func<object>
做了类似的事情,但遗憾的是,由于它不是一个界面而且从Func<TIn, TOut>
到Func<object>
的投射不起作用,因此不起作用
答案 2 :(得分:1)
这是一个简单的解决方案:
class TypeConverter
{
private readonly IDictionary<Type, Delegate> map = new Dictionary<Type, Delegate>();
public void Register<TInput, TOutput>(Converter<TInput, TOutput> converter)
{
if (converter == null)
throw new ArgumentNullException("converter");
this.map.Add(typeof(TInput), converter);
}
public TOutput Convert<TInput, TOutput>(TInput value)
{
return ((Converter<TInput, TOutput>)this.map[typeof(TInput)])(value);
}
public object Convert(object value)
{
if (value == null)
throw new ArgumentNullException("value");
return this.map[value.GetType()].DynamicInvoke(value);
}
}
以下是如何使用它:
static void Main(string[] args)
{
var converter = new TypeConverter();
converter.Register<int, string>(value => (value + 1).ToString());
string x = converter.Convert<int, string>(5);
object boxedInt = 5;
string y = (string)converter.Convert(boxedInt);
}
请注意,此解决方案使用的Delegate.DynamicInvoke速度相当慢,因此如果您正在寻找性能更高的解决方案,则应该使用已经提到的包含System.Converter委托和实现接口的泛型类这暴露了弱类型的转换方法。
答案 3 :(得分:0)
public static T ConvertTo<T>(object value)
{
try
{
return (T)Convert.ChangeType(value, typeof(T), CultureInfo.InvariantCulture);
}
catch(Exception ex)
{
return (T)(typeof(T).IsValueType ? Activator.CreateInstance(typeof(T)) : null);
}
}
您可以使用此方法。以下是如何使用它的示例:
string test = "5";
decimal d = ConvertTo<decimal>(test);