你能返回一个基于泛型类型的函数吗?

时间:2010-12-15 17:13:25

标签: c# linq

我正在编写一个简单的概念证明,本质上应该是一个解析器生成器。

基本上我正在寻找一种方法,我可以编写一个函数,它将返回一个从字符串转换为给定类型的某个对象的函数 - 我希望能够在本质上执行以下操作:

Func<string, double> ConvertToDouble = BuildConverter(typeof(0.0));

显然这是一个非常人为的例子 - 但如果我可以做简单的版本,那么我应该能够做更复杂的版本!

FWIW,我最终要做的是将一串值映射到一个类,但为了使它尽可能灵活,我想通过一个函数返回一个函数来完成它转换。在功能方面,我想我想要的东西看起来像这样:

a -> (string -> a)

作为第一次尝试,我尝试过这样做:

public static Func<string, T> BuildParser<T>(T t)
    {
      if (t is String)
        return new Func<string, T>(x => x.ToString());
      if (t is double)
        return new Func<string, T>(x => double.Parse(x));
    }

这根本不起作用,但是让我感到有点担心我应该采取什么方法 - 所以任何帮助都会非常感激!

4 个答案:

答案 0 :(得分:0)

我猜你想要在编译时验证特定的行为。为什么不直接调用Convert或编写单独的方法?你的if语句所完成的就是承担应该选择适当转换方法的程序员的角色。

如果您想要在运行时选择行为,则应返回Func<string, object>,并使该方法不是通用的。

在方法中使用泛型类型T的问题是每次调用方法时T都是固定的,并且方法中的逻辑假设T在一次调用中变化(在一种情况下T是一个字符串,在另一种情况T是小数)。编译器无法对此进行排序 - 它需要允许两个可返回实例具有相同的类型。

答案 1 :(得分:0)

我不确定你到底想要做什么,但这会有什么帮助呢?

var stringParser = GetParser<string>();
string s = stringParser("test");

var doubleParser = GetParser<double>();
double d = doubleParser("42");

// ...

public static Func<string, T> GetParser<T>()
{
    return (Func<string, T>)_parserCache[typeof(T)];
}

private static readonly Dictionary<Type, Delegate> _parserCache =
    new Dictionary<Type, Delegate>
        {
            { typeof(string), new Func<string, string>(x => x) },
            { typeof(double), new Func<string, double>(x => double.Parse(x)) }
            // etc
        };

答案 2 :(得分:0)

您不能将classstruct类型混合使用。除此之外,它将起作用。

请参阅以下代码:

private void Testing() {
    var func = BuildParserStruct<double>();
    double value = func("5");
}

public static Func<string, T> BuildParserClass<T>() where T : class
{
    return x => x as T;
}

public static Func<string, T> BuildParserStruct<T>() where T : struct
{
    return (x => (T)Convert.ChangeType(x, typeof(double)));
}

答案 3 :(得分:0)

ADO.Net有一个Execute Scalar函数,它总是困扰我,因为它返回一个对象。您可以编写通用包装函数来返回适当的类型。当然,这假设你知道将返回什么类型。

有点简化:

    public T ExecuteScalar<T>()
    {
        return (T)Command.ExecuteScalar();
    }