2010-01-08 38 views
1

我有一个泛型类,我需要约束只值类型(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 
     } 
    } 
} 

约束吨至struct不工作,我真的想避免装箱/如果可能的话拆箱。有任何想法吗?

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

回答

4

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

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

你可能会更好离开约束为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); 
} 

您可以阅读有关available constraints here。唯一可用的约束条件是:

  • 结构(可选)
  • 新()(可选)
  • 接口约束(可选,多个允许)
  • 基类约束(可选,只允许一个)
  • 赤裸裸的限制(如其中T:TResult)
+0

现在我想知道...... CLR是否允许'System.Int32'作为约束?我们可以用Jon Skeet在Unconstrained Melody上使用的相同技巧吗? –

+0

@Martinho:不,你不能。那又有什么意义呢?像MyFunc (T num)这样的方法签名,其中T:int将与“MyFunc(int num)”实际上相同。 – LukeH

+0

代表解决方案似乎是最简单的。构造函数在库的内部(即用户可以访问创建的对象,但不能创建它们),因此传递额外的参数没有什么大不了的。 –

4

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

简而言之:为什么是通用的,如果你根据类型做了不同的事情(不知何故,这种做法无论对于传入的任何类型都会做同样的事情)。我想你可能真的想用Convert.ChangeType

事情是这样的:

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

像Bushkin先生说,你不能这样做。所以你另外的选择是简单地为每个基本类型做一些方法的重载。另外,假设你不必处理原始类型,但你真的想要处理所有的结构 - 它仍然是不可能的,因为结构不能保证实现一个(迄今为止虚构的)接口所谓的IParsable被铸成T.

1

我想我在这里看不到数值...为什么不使用Convert类?

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

它的优点是可以与任何类型的转换器一起工作(或者您可以在运行时自行添加)。它确实有拳击,但真的,it isn't so bad。如果这是你最大的问题,那么你会以错误的方式去做。

+0

我运行上面的代码,而不是只调用Parse方法,我发现它慢了5倍。不知道是否会同意Skeet的博客,拳击是“在噪音”。我同意你不应该跳过设计篮圈来避免它,但如果可能的话应该避免。 –

+0

正是我在找的东西。谢谢@Marc Gravel。 – JCallico