使用已注册的lambda将一种类型转换为另一种类型的类

时间:2015-02-14 15:35:18

标签: c# lambda

我想上课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 :/
}

4 个答案:

答案 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);