我正在尝试编写一个通用结构来解析可为空的类型。
我有几个问题:
我无法继承Nullable<T>
,因为它是一个结构:
public struct NullableParsable<T> : Nullable<T> where T : struct { }
接口列表中的T类型不是接口
所以我尝试:
public struct NullableParsable<T> where T : struct
{
public static T? Parse(string s)
{
T? result = null;
string tName = typeof(T).Name;
switch(tName)
{
case "Int32": result = string.IsNullOrEmpty(s) ? null : (int?)int.Parse(s); break;
case "Decimal": result = string.IsNullOrEmpty(s) ? null : (decimal?)decimal.Parse(s); break;
default: throw new NotImplementedException("unmanaged type: "+ tName);
}
return result;
}
}
我无法将int
投射到T
或int?
投射到T?
。
我想在结构类型(也许是一个枚举)之间进行切换的一种简单方法,暂时在类型名称typeof(T).Name
之间进行切换。也许是反射机制来调用Parse
...
在此提琴中查看完整的代码:https://dotnetfiddle.net/x6kHzx
关于如何正确实现此功能的任何想法?
答案 0 :(得分:1)
由于您将无法处理所有struct
(在硬编码列表之外,没有Parse
可以通过反射定位),因此我建议在{{1} },对于您知道如何支持这些类型的。例如
string
无论如何,您在这里都不会从泛型中受益,因为所有public static class ParseExtensions {
public static int? ParseInt(this string input)
{
if(Int32.TryParse(input,out var result)
{
return result;
}
return null;
}
public static DateTime? ParseDateTime(this string input)
{
if(DateTime.TryParse(input, out var result)
{
return result;
}
return null;
}
}
/ Parse
方法都是单独的方法,它们碰巧共享一个名称。他们没有共享的继承/接口祖先。
答案 1 :(得分:1)
除了已经给出的建议之外,您可以做的是使用字典而不是switch语句来使它更具动态性。这不会改变只能解析指定的类型。
例如,您可以创建一个知道如何解析这些类型的类:
public class NullableParsable
{
private static readonly Dictionary<string, Func<string, object>> _parsers =
new Dictionary<string, Func<string, object>>();
public static void Register<T>(Func<string, T?> parser)
where T : struct
{
var key = typeof(T).FullName;
_parsers.Add(key, x => parser(x));
}
public static T? Parse<T>(string value)
where T : struct
{
var key = typeof(T).FullName;
if (_parsers.TryGetValue(key, out var parser))
{
if (string.IsNullOrEmpty(value))
{
return null;
}
return (T?) parser(value);
}
throw new NotSupportedException("Not sure how to map this type");
}
}
然后,指定如何解析特定类型:
NullableParsable.Register<int>(s => int.Parse(s));
NullableParsable.Register<decimal>(s => decimal.Parse(s));
NullableParsable.Register<Guid>(s => Guid.Parse(s));
用法示例:
int? result1 = NullableParsable.Parse<int>("123");
decimal? result2 = NullableParsable.Parse<decimal>("123");
Guid? result3 = NullableParsable.Parse<Guid>(Guid.NewGuid().ToString("D"));
答案 2 :(得分:-1)
实际上,我只需要将结果声明为dynamic
,然后就可以为其分配一个Nullable
并将其返回为T?
:
public static T? Parse(string s)
{
dynamic result = null;
int intValue;
result = int.TryParse(s, out intValue) ? (int?)intValue : null;
return result;
}
有了关系,我可以调用Parse:
public static T? Parse(string s)
{
dynamic result = null;
Type type = typeof(T);
string tName = type.Name;
MethodInfo methodInfo = type.GetMethod("Parse", new[] { typeof(string) });
result = methodInfo.Invoke(null, new[] { s });
return result;
}
更好,我可以调用TryParse以避免try / catch:
public static T? Parse(string s)
{
Type type = typeof(T);
string tName = type.Name;
MethodInfo methodInfo = type.GetMethod("TryParse", new[] { typeof(string), type.MakeByRefType() });
object[] args = new object[] { s, null };
bool parsed = (bool)methodInfo.Invoke(null, args);
dynamic result = parsed ? args[1] : null;
return result;
}
更新了fiddle