【问题标题】:Invoke Func without knowing its return type at compile time在编译时调用 Func 而不知道它的返回类型
【发布时间】:2015-01-30 22:38:56
【问题描述】:

我正在尝试写一些东西,但我遇到了死胡同。我有以下代码:

public class ObjectConverter
{
    private Dictionary<Type, object> m_Conversions = new Dictionary<Type, object>();

    public void AddConversion<TOut>(Func<object, TOut> conversion)
    {
        m_Conversions[typeof(TOut)] = conversion;
    }

    public T Convert<T>(object value)
    {
        var conversion = (Func<object, T>) m_Conversions[typeof(T)];
        return conversion(value);
    }
}

这是对真实事物的简化,但基本上它允许将对象转换为我们为其定义了转换的任何类型。 这样你就可以做类似的事情:

// Intialization
converter.AddConversion(x => Convert.ToInt32(x));

// Some other place
converter.Convert<int>("12");

到目前为止一切都很好,但复杂的是我想写一个非通用的转换版本

object Convert(object value, Type type)
{
    var conversion = m_Conversions[type];
    // ???
}

我该怎么做?我想过做类似的事情:

object Convert(object value, Type type)
{
    var conversion = m_Conversions[type];
    var funcType = typeof(Func<,>).MakeGenericType(typeof(object), type);
    var invoke = funcType.GetMethod("Invoke");
    return invoke.Invoke(conversion, new object[] { value });
}

但它似乎非常低效。你能想出更好的方法吗?

【问题讨论】:

  • 为什么你认为它效率低?
  • 因为反射。它可能没有现在那么糟糕,但我想知道是否有更好的方法来解决它,结果证明是有的。

标签: c# reflection func


【解决方案1】:

Func is covariant,例如每个Func&lt;object, string&gt; 都会返回object,因此它可以安全地转换为Func&lt;object, object&gt;。所以在你的情况下,你根本不需要反思。

public class ObjectConverter
{
    private Dictionary<Type, Func<object, object>> m_Conversions = new Dictionary<Type, Func<object, object>>();

    public void AddConversion<TOut>(Func<object, TOut> conversion) 
    {
        // need this to support TOut as value type. 
        m_Conversions[typeof(TOut)] = obj => conversion(obj);
    }

    public T Convert<T>(object value)
    {
        return (T) Convert(value, typeof(T));
    }

    object Convert(object value, Type type)
    {
        var conversion = m_Conversions[type];
        return conversion(value);
    }
}

【讨论】:

  • 请注意:您只能将 Func 转换为 Func 如果您有“where T : class”约束(这完全有道理),所以我最终做了您所做的(将 Func 包装在 Func 中)而不是强制转换,因为我需要支持值类型
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-15
相关资源
最近更新 更多