将值类型转换为泛型

Bri*_*ett 2 c# generics

我有一个泛型类,我需要约束只有值类型(int,float等).我有一个方法,根据类型的测试调用Parse方法.例如:

class MyClass<T>
{
    ...

    private static T ParseEntry(string entry)
    {
        if(typeof(T) == typeof(float))
        {
            return (T) float.Parse(entry);
        }

        if(typeof(T) == typeof(int))
        {
            .... you get the idea
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

限制T struct不起作用,我真的想避免装箱/拆箱,如果可能的话.有任何想法吗?

编辑:更深入地了解这一点.我注意到在库中我正在开发两个类具有非常相似的属性/方法等.唯一的区别是基础类型的数据(int或float).这引出了我的泛型设计.唯一的挂起是因为调用特定的Parse方法取决于它是float还是int.我可以用拳击/拆箱来绕过它,但我真的想尽可能避免这种情况.

Mar*_*ell 11

private static T ParseEntry(string entry)
{
    TypeConverter conv = TypeDescriptor.GetConverter(typeof(T));
    return (T) conv.ConvertFromString(entry);
}
Run Code Online (Sandbox Code Playgroud)

它具有使用类型转换器处理任何类型的优点(或者您可以在运行时添加自己的类型转换器).它确实有拳击,但实际上,它并没有那么糟糕.如果那是你最大的问题,那你就是错误的做法.


LBu*_*kin 6

不幸的是,您无法创建描述类型的约束.你不能写,例如:

class MyClass<T> where T : int { ... } // won't compile
Run Code Online (Sandbox Code Playgroud)

您可能最好不要使用约束struct,但添加一些运行时检查以确保在实例化类时T只是受支持的类型之一.既然你没有多说你打算如何使用你的课程 - 很难提供关于如何实现更好的类型安全的替代设计建议.

编辑:你应该看看Marc和其他人推荐的类型转换器选项.这似乎是要走的路.

编辑:发生在我身上的一个可能的想法是使Parse()方法实际上是一个委托:Func<string,T>- 你在施工期间分配.这将使您有可能:

  1. 避免低效和笨拙的if/else逻辑.
  2. 将类的未来使用改进为其他值类型(结构,BigDecimal等)

这是我的意思的代码示例:

class MyClass<T>
{
    private readonly Func<string,T> ParseEntry;

    public MyClass( Func<string,T> parser )    
    {
        ParseEntry = parser;
    }
}

public static class AvailableParsers
{
    public static Func<string,int> ParseInt = s => int.Parse( s );
    public static Func<string,float> ParseFloat = s => float.Parse(s);
}
Run Code Online (Sandbox Code Playgroud)

您可以在此处阅读可用的约束.唯一可用的限制是:

  • struct(可选)
  • new()(可选)
  • 接口约束(可选,允许多个)
  • 基类约束(可选,只允许一个)
  • 裸约束(例如T:TResult)


Ben*_*zun 5

也许愚蠢,但是 - 如果你在谈论一组有限的类型,你为什么不重载这个方法呢?像*Writer.Write()方法一样,每个"基础"类型都有重载?

简而言之:为什么是通用的,如果你根据类型做了不同的事情(这会以某种方式违背为传递任何类型做同样事情的目的)?


编辑:考虑使用情况我认为您可能实际上想要使用Convert.ChangeType.

像这样的东西:

class MyClass<T> where T: IConvertible
{
    private static T ParseEntry(string entry)
    {
        return (T)Convert.ChangeType(entry, typeof(T));
    }
}
Run Code Online (Sandbox Code Playgroud)