C# 可为null的泛型可解析类

C# 可为null的泛型可解析类,c#,class,parsing,C#,Class,Parsing,我试图编写一个泛型结构来解析可为null的类型 我有几个问题: 我无法继承Nullable,因为它是一个结构: public struct NullableParsable<T> : Nullable<T> where T : struct { } 接口列表中的类型T不是接口 因此,我尝试: public struct NullableParsable<T> where T : struct { public static T

我试图编写一个泛型结构来解析可为null的类型

我有几个问题:

我无法继承Nullable,因为它是一个结构:

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

我想要一个在结构类型之间切换的简单方法,可能是一个枚举,目前我在类型名称之间切换typeofT.Name。或者可能是一种反射机制来调用解析

请参阅本手册中的完整代码:


你知道如何正确地实现这个功能吗?

因为你不能处理硬编码列表之外的所有结构,没有可通过反射定位的解析,所以我推荐一些字符串扩展方法,用于你知道如何支持的类型。例如


不管怎样,这里的泛型没有任何好处,因为所有Parse/TryParse方法都是单独的方法,只是碰巧共享一个名称。它们没有共享的继承/接口祖先。

事实上,我只需要将我的结果声明为动态,然后我就可以为它分配一个可为null的值,并将其作为t?返回:

使用Relefection,我可以调用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;
}
更新

相关职位: ,

除了已经给出的建议外,您可以使用字典而不是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"));

如何在这里编写有意义的通用实现?解析INT和解析DateTime看起来很不一样,更不用说自定义结构了。@Damien_The_不相信我的人,我只需要调用相应类型的解析函数。这很像我自己使用的东西-只是名称不同-DateTime有一些有用的重载来处理不同的格式和类似的东西+1.既然你也可以用各种各样的作品,为什么不直接用TryParse呢?但它并不优雅,我想要一些东西generic@sinsedrix-这里没有必要写一个泛型。正如我试图指出的,在这里使用泛型添加的所有代码都将在运行时失败,因为您实际上无法编写泛型实现,并且您将切换到已知类型和/或依赖反射。您正在使用编译时类型安全性,并将其转化为运行时错误。我更喜欢打开类名,而不是编写N methodsdynamic。这里不需要,可以用t/t?@Caramiriel dynamic needed表示,因为我无法将对象强制转换为t/t?。
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"));