2010-12-15 48 views
2

我正在写一个简单的概念证明,应该是什么,实质上是一个解析器生成器。你可以返回一个基于泛型类型的函数吗?

基本上我正在寻找我能写会返回一个字符串转换为给定类型的一些物体的功能的函数的方式 - 我希望能够做到在本质上是以下几点:

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

很明显,这是一个非常人为的例子 - 但如果我可以做简单的版本,那么我应该可以做更复杂的版本!我最终试图做的是将一个值的字符串映射到一个类,但为了使它尽可能灵活,我想通过一个函数返回一个函数来做到这一点转换。在功能方面,我觉得我想要的东西,看起来像这样:

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)); 
    } 

这并不在所有的工作,但它让我感觉有点卡住,我应该采取什么方法 - 所以任何帮助都将不胜感激!

+3

你似乎缺少泛型的点,如果你在你的通用功能寻找_types_。 – Oded 2010-12-15 17:17:40

+2

如果您想要运行时决策,那么您不应该使用泛型。如果你想编译时决定,那么你不应该使用“是”。 – 2010-12-15 17:18:20

+0

@Oded - 我不确定我是否同意,我只是在寻找特定类型的多态。 – MrBear 2010-12-16 13:00:34

回答

0

你不能struct类型混合class。除此之外,它会起作用。

请参见下面的代码:

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))); 
} 
+0

看起来很有趣!我会试一试 - 我完全忘了'where T:'语法。 – MrBear 2010-12-16 09:17:42

+0

是什么让你觉得你不能“将'class'与'struct'类型混合?这可以通过一个'BuildParser '方法完成;如果你不想要,你不需要单独的'BuildParserClass '和'BuildParserStruct '方法。 (以我的答案为例) – LukeH 2010-12-20 00:55:43

+0

够公平的。我应该说的是,泛型方法不能在不使用反射的情况下实例化结构和类类型(或派生类型)。这个限制不影响你的解决方案,因为你的泛型方法没有实例化任何东西......我发现你的解决方案很聪明,即使有限(在处理30种不同的类型时需要30个项目的缓存,等等)... – rsenna 2010-12-27 18:35:41

0

我猜你想在编译时验证特定的行为。为什么不直接拨打Convert或编写单独的方法来使用?如果您的陈述完成了所有的事情,那么程序员应该选择恰当的转换方法。

如果您想要在运行时选择行为,则应返回Func<string, object>,并使该方法非泛型。

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

+0

就我的例子而言,你是正确的 - 它只是一个概念证明。最终,我有一个消息系统,以逗号分隔的字符串发送消息,每个消息都可以映射到一个类(或一个结构体)。这意味着只要有人在这里使用该消息系统编写应用程序,他们就需要手动编写他们如何将其映射到课程的代码。本质上,我想要做的是通过编写一个映射器生成器来实现自动化。 – MrBear 2010-12-16 07:57:51

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 
     }; 
0

ADO.Net有一个执行标量函数,一直困扰着我,因为它返回一个对象。你可以编写一个通用包装函数来返回适当的类型。当然这假定你知道什么类型将被返回。

有些简化:

public T ExecuteScalar<T>() 
    { 
     return (T)Command.ExecuteScalar(); 
    } 
相关问题