i have the following method that returns a "value parser" delegate according to the input type. it works fine but i'd like to get rid of the switch statements and type checks and be able to return a value parser delegate for any type that has a TryParse() method.
internal static Func<object?, (bool isSuccess, object value)>? ValueParser(this Type type)
{
type = Nullable.GetUnderlyingType(type) ?? type;
if (type.IsEnum)
return input => (Enum.TryParse(type, ToString(input), out var res), res!);
switch (Type.GetTypeCode(type))
{
case TypeCode.String:
return input => (true, input!);
case TypeCode.Boolean:
return input => (bool.TryParse(ToString(input), out var res), res);
case TypeCode.DateTime:
return input => (DateTime.TryParse(ToString(input), out var res), res);
//other supported types go here...
case TypeCode.Object:
if (type == Types.Guid)
{
return input => (Guid.TryParse(ToString(input), out var res), res);
}
else if (type == Types.TimeSpan)
{
return input => (TimeSpan.TryParse(ToString(input), out var res), res!);
}
break;
}
return null; //unsupported types will cause a null return
static string? ToString(object? value)
{
if (value is string x)
return x;
return value?.ToString();
}
}
i believe the solution would be to build an expression tree something like below. but i haven't got the slightest clue how to go about building an expression tree correctly. so far all i have is the following:
internal static Func<object?, (bool isSuccess, object value)>? ValueParser(this Type type)
{
type = Nullable.GetUnderlyingType(type) ?? type;
var inputParam = Expression.Parameter(typeof(string), "input");
if (type == Types.String)
{
//no need for conversion if input type is string. so delegate should simply return a tuple (true,"inputValue").
var returnTarget = Expression.Label(type);
var returnCall = Expression.Return(returnTarget, inputParam);
}
var parsedVar = Expression.Variable(type, "parsed");
var tryParseCall = Expression.Call(
type,
"TryParse",
null,
inputParam,
parsedVar);
//need to compile the expression and return here.
//if the input type doesn't have a TryParse() method, null should be returned.
//also not sure if we need Expression.Convert() to handle value types.
}
i've been banging my head against the wall on this for a few days without much success. would really appreciate any help you can provide. thanks!
type, find its staticTryParsemethod, and call that?Func<object?, (bool isSuccess, object value)>?because the consumers are going to cache it and use whenever needed.Typebool (string, out T)signature, it's easy for callers to pass aTryParsemethod if one exists, easy to adapt other methods for other types, and is type safe at compile time...