【问题标题】:Why can't System.Array be a type constraint?为什么 System.Array 不能是类型约束?
【发布时间】:2013-02-10 05:29:12
【问题描述】:

我正在处理一个包含几种不同类型数组的小项目(例如double[]float[]int[]。出于验证/测试/健全的目的,我将其中一些数组打印到控制台。所以我有多个如下所示的函数(在此示例中进行了简化 - 假设我只处理单维数组):

void Print(float[] a) // prints an array of floats
{
    for (int i = 0; i < a.Length; i++)
    {
        Console.Write(a[i]);
    }
}

void Print(double[] a) // prints an array of doubles
{
    for (int i = 0; i < a.Length; i++)
    {
        Console.Write(a[i]);
    }
}

以我无限的智慧,我认为我可以通过简单地创建这些函数的通用版本来减少一些代码重复。所以我尝试了这个:

void Print<T>(T t) where T : Array
{
    for (int i = 0; i < t.Length; i++)
    {
        Console.Write(t.GetValue(i));
    }
}

Intellisense 没有抱怨,但编译器失败并出现一个非常有趣的错误:

Constraint cannot be special class 'System.Array'

我一直在寻找解释(类似于Object 或密封类,但除了提到on msdn 之外,还没有找到太多。谁能给我解释一下为什么这是case?为什么不能指定System.Array的类型约束?

p.s.:在输入这​​个的时候,我意识到我可以更轻松地完成我最初想要的事情,只需一个简单的函数:

void Print(System.Array a)
{
    for (int i = 0; i < a.Length; i++)
    {
        Console.Write(a.GetValue(i));
    }
}

这就是为什么编译器中有一个特殊的数组规则吗?

【问题讨论】:

  • 所以目前还没有实际的答案。

标签: c# .net arrays compiler-errors generic-constraints


【解决方案1】:

执行您想要的操作的适当语法是这样的:

void Print<T>(T[] array)
{
    for (int i = 0; i < array.Length; i++)
    {
        Console.Write(array[i]);
    }
}

【讨论】:

  • 有道理,但我还是很好奇为什么我不能有Array的基类类型约束...
  • 另外,出于好奇,这与使用Array 类型的参数有什么不同?如果我使用Array,会有一些拳击吗?
  • @vlad 没有装箱,因为数组是引用类型,而不是值类型,尽管与类型化数组不同,您将从中取出的对象装箱。这也不一样,因为 Array 也可以是 2、3 或 N 维数组,或者不是 0 索引的数组。
  • 也有道理。为了清楚起见,您是说编译器根本不允许我尝试编写的内容,因为正确的语法是您发布的内容?也就是where T : Array能做的所有事情都可以在参数列表里做?
  • @vlad 如果您不知道传入数组的维度或正在处理1 个(或任何非零)索引数组。
【解决方案2】:

如果从字面上理解这个问题,那么有一个Array 约束是没有用的。这与拥有ValueType 约束是一样的,因为它实际上并不检查您是否使用值类型作为泛型参数,而是检查您传递的类型是否可分配给ValueType
因此,您甚至可以将 Array 作为通用参数传递,就可以了。

真正有用的是有一个 array 约束,允许从 Array 派生的任何类型,但不是 Array 本身:

void Print<TArr>(TArr t) where TArr : array //or [*] or other fancy syntax

其中T 可以是[][,][,,][,,,],等等。唯一超过非泛型的Array 参数是我们知道数组的元素类型。

解决此问题的另一种方法是创建一个自定义 Array&lt;T&gt; 类,其中包含 T[]T[,]T[,,] 等隐式运算符重载。

编辑:
即使在 CIL(当前)中也无法实现这一点,因为 int[,]Array 在任何接口或构造函数中都没有区别。我们需要where T : Array but not Array itself 约束。

【讨论】:

  • 它不会完全没用。如果不是因为禁止,人们可以写一个CopyAndReverseArraySegment&lt;T&gt;(T dest, T source, int start, int length) where T:System.Array 并让它接受源或目标中的一个或两个是System.Array 的调用,但仍然拒绝sourcedest 是不兼容的数组类型的调用。事实上,我不相信有一种方法可以允许 System.Array 作为其中一个参数的特定类型,而没有该类型的任何派生也被认为是可以接受的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-22
  • 2019-03-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-10
相关资源
最近更新 更多