将值类型转换为泛型

时间:2010-01-08 21:52:24

标签: 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
        }
    }
}

将T约束到struct不起作用,如果可能的话我真的想避免装箱/拆箱。有什么想法吗?

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

5 个答案:

答案 0 :(得分:11)

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

具有使用类型转换器处理任何类型的优点(或者您可以在运行时添加自己的类型转换器)。它确实有拳击,但真的,it isn't so bad。如果那是你最大的问题,那你就是错误的做法。

答案 1 :(得分:5)

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

class MyClass<T> where T : int { ... } // won't compile

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

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

编辑:我想到的一个可能的想法是让Parse()方法实际上成为委托:Func<string,T> - 您在构建期间分配。这将使您能够:

  1. 避免使用低效和笨拙的if / else逻辑。
  2. 将您的类的未来使用改进为其他值类型(结构,BigDecimal等)
  3. 以下是我的意思的代码示例:

    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);
    }
    

    您可以阅读available constraints here。唯一可用的限制是:

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

答案 2 :(得分:5)

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

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


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

这样的事情:

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

答案 3 :(得分:1)

我想我没有看到这里的价值......为什么不使用Convert类?

答案 4 :(得分:0)

像布什金先生说的那样,你不能这样做。因此,您可以选择为每种基本类型简单地对方法进行多次重载。

另外,想象一下你不必处理原始类型,但是你真的想处理所有结构 - 它仍然是不可能的,因为结构不能保证实现一个(迄今为止想象的)接口IParsable被投入T。