关于c#:如何使用约束将T限制为值类型?

 2021-04-27 

How to restrict T to value types using a constraint?

我想使用约束来限制N可以采用的类型。我希望将N限制为int或小数。

1
2
3
4
public static Chart PopulateInto<T, N>(List< T > yAxis, List<N> xAxis) where N : int, decimal
{
    // Do stuff here
}

任何帮助表示赞赏...


不可能将通用参数限制为特定的值类型。

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


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

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

如果允许值类型使用它,而您不能从这些类型继承,则可以有效地将自己限制为该类型。

因此您无法执行此操作,但是您有几种选择:

  • 您可以在没有约束的情况下声明它,并在运行时处理问题。我不会推荐这种方式
  • 您可以声明采用您感兴趣的特定类型的重载。

    由于您只有两种类型,所以我建议这样做。

这是您要声明的重载:

1
2
3
4
5
6
7
8
9
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,但是您的实现仍然是通用的。不知道确切的"在这里做东西"意味着什么是不可能的,但是无论如何这是下面的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
}


没有约束可以做到这一点。但是,假设PopulateInto可以与泛型N一起使用,另一种方法是使核心算法algorihtm泛型和私有,并提供2个公共重载,分别采用intdecimal。这会产生类似的效果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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 {
  ...
}


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

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


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

要覆盖通常由Value Types表示的所有类型(包括空值类型,甚至包括string,即使从技术上讲它是引用类型),也需要3个重载:

1
2
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文档中的信息:

where T : struct The type argument must be a non-nullable value type.


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