Can you return a function that's based on a generic type?
I'm writing a simple 开发者_开发技巧proof of concept for what should be, in essence, a parser generator.
Basically I'm looking for a way that I can write a function that will return a function that converts from a string to some object of a given type - I want to be able to do the following in essence:
Func<string, double> ConvertToDouble = BuildConverter(typeof(0.0));
Obviously this is a pretty contrived example - but if I can do the simple version then I ought to be able to do the more complicated version!
FWIW, what I'm ultimately trying to do is to map a string of values onto a class, but to make it as flexible as possible, I want to do it by having a function that will return a function that does the conversion. In functional terms, I think I want something that looks like this:
a -> (string -> a)
As a first try, I've tried doing this:
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));
}
Which doesn't work at all, but it leaves me feeling a bit stuck as to what approach I ought to be taking - so any help at all would be greatly appreciated!
You cannot mix class
with struct
types. Beyond that, it will work.
See the code below:
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)));
}
I'm guessing that you want specific behaviors verified at compile time. Why not just call Convert or write individual methods to use? All that your if statements accomplish is to take role of the programmer who should be chosing the appropriate conversion method.
If you want behaviors chosen at runtime, you should return Func<string, object>
, and make the method non-generic.
The issue with using a generic Type T in the method is that T is fixed for each call to the method, and the logic in the method supposes T to vary in a single call (in one case T is a string, in another case T is a decimal). The compiler cannot sort this out - it would need to allow both returnable instances to have the same type.
I'm not certain of exactly what you're trying to do, but would something like this help?
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
};
ADO.Net has an Execute Scalar function that always bothered me because it returns an object. You can write a generic wrapper function to return the appropriate type. Of course this assumes that you know what type will be returned.
Somewhat simplified:
public T ExecuteScalar<T>()
{
return (T)Command.ExecuteScalar();
}
精彩评论