如何使用约束将 T 限制为值类型?

Posted

技术标签:

【中文标题】如何使用约束将 T 限制为值类型?【英文标题】:How to restrict T to value types using a constraint? 【发布时间】:2010-11-05 19:52:55 【问题描述】:

我想限制 N 可以使用约束的可能类型。我希望将 N 限制为 int 或 decimal。

public static Chart PopulateInto<T, N>(List<T> yAxis, List<N> xAxis) where N : int, decimal

    // Do stuff here

任何帮助表示赞赏...

【问题讨论】:

如果您只关心这两种类型,我认为您可以重载该方法。当然是 4 次重载,但这还不错。 【参考方案1】:

不能将泛型参数限制为特定的值类型。

但是,您可以通过添加 where N : struct 将其强制为 a 值类型或 struct,仅此而已。

【讨论】:

另一种处理方法是为 intdecimal 列表设置特定的重载。【参考方案2】:

不幸的是,不能指定只允许特定值类型的泛型类型约束。更重要的是,即使允许也没有多大意义。

您可以将类指定为通用约束,但这是因为您可以从类继承,因此该约束设置了允许使用的类型的最小阈值。

如果值类型允许这样做,而您不能从这些类型继承,那么您实际上会将自己限制为仅使用该类型。

因此你不能这样做,但你有几个选择:

您可以在没有约束的情况下声明它,并在运行时处理问题。 我不推荐这种方式

您可以声明采用您感兴趣的特定类型的重载。

由于您只有两种这样的类型,因此我建议您这样做。

这里是你要声明的重载:

public static Chart PopulateInto<T>(List<T> yAxis, List<int> xAxis)

    // Do stuff here


public static Chart PopulateInto<T>(List<T> yAxis, List<decimal> xAxis)

    // Do stuff here


现在,另外,如果您对这些值的处理并不真正依赖于这些类型的数值质量,您只想限制可以处理的类型,那么您可以随时声明您的原始方法,私下,并从您的重载中调用此方法。这仍然会将您的代码限制为只允许intdecimal公开,但您的实现仍然是通用的。如果不确切知道“在这里做事”意味着什么,就无法判断这是否是一个可行的选择,但无论如何这里是代码:

public static Chart PopulateInto<T>(List<T> yAxis, List<int> xAxis)

    return PopulateInto<T, int>(yAxis, xAxis);


public static Chart PopulateInto<T>(List<T> yAxis, List<decimal> xAxis)

    return PopulateInto<T, decimal>(yAxis, xAxis);


private static Chart PopulateInto<T, N>(List<T> yAxis, List<N> xAxis) where N : struct

    // Do stuff here

【讨论】:

我的泛型已关闭,这就是我在周五晚上写答案时得到的,让我更正一下。 感谢您的建设性批评。不幸的是,标题中的问题具有误导性,因为如果我们将自己限制在这个范围内,那么答案很简单:where N : struct。然而,真正的问题只有一个真实的、确定的答案,那就是“这在当前允许的 C# 语法中是不可能的”。不过,我已经扩展了我的答案以涵盖所有选项,希望它会浪费更少的时间。【参考方案3】:

没有办法通过约束来做到这一点。不过,另一种方法是,假设PopulateInto 可以与通用 N 一起工作,是使核心算法通用和私有,并提供 2 个公共重载,分别采用 intdecimal。这将产生类似的效果

public static Chart PopulateInto<T>(
  List<T> yAxis, 
  List<decimal> xAxis) 

  return PopulateIntoCore(yAxis, xAxis);


public static Chart PopulateInto<T>(
  List<T> yAxis, 
  List<int> xAxis) 

  return PopulateIntoCore(yAxis, xAxis);


private static Chart PopulateIntoCore<T, N>(
  List<T> yAxis, 
  List<N> xAxis) where N : struct 
  ...

【讨论】:

@Mark,是的,这将是我回答的关键;)已修复【参考方案4】:

正如 Pieter 所说,您不能对此使用编译时检查。但是,您可以在运行时执行以下操作:

if(!(typeof(N).equals(typeof(int32))) && !(typeof(N).equals(typeof(decimal))))
  // do something

【讨论】:

是的,为什么不呢。抛出 InvalidOperationException。【参考方案5】:

回答标题中的问题,而不是问题的正文。

要涵盖Value Types(包括Nullable Value Types 和string,即使它是technically a Reference type)通常表示的所有 类型,您需要3 个重载:

public void Foo<T>(T arg) where T : struct
public void Foo<T?>(T? arg) where T : struct
public void Foo<string>(string arg)

来自MSDN Docs on generic constraints:

where T : struct type 参数必须是不可为空的值类型。

【讨论】:

【参考方案6】:

你可以得到的壁橱是 Where T: struct, IComparable, IFormattable, IConvertible。 所有值类型都实现了这些接口。

【讨论】:

以上是关于如何使用约束将 T 限制为值类型?的主要内容,如果未能解决你的问题,请参考以下文章

C#泛型 类型约束

C#如何将类型Type作为泛型T的参数T传递

Sql PIVOT,如何使用 PIVOT 将结果中的 NULL 转换为值 0

是否存在将我的泛型方法限制为数字类型的约束?

where(泛型类型约束)

泛型约束