问题
I'm working on a small project with a few different types of arrays (e.g. double[]
, float[]
, int[]
. For verification / testing / sanity purposes, I'm printing out some of these arrays to the console as I go along. So I have multiple functions that look like these below (simplified for this example - assume I'm only dealing with single-dimension arrays):
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]);
}
}
I, in my infinite wisdom, thought I could reduce some of the code duplication by simply creating a generic version of these functions. So I tried this:
void Print<T>(T t) where T : Array
{
for (int i = 0; i < t.Length; i++)
{
Console.Write(t.GetValue(i));
}
}
Intellisense isn't complaining, but the compiler fails with a very interesting error:
Constraint cannot be special class 'System.Array'
I've looked for an explanation (similar to Object
or sealed classes, but haven't found much, besides a mention on msdn. Can anyone explain to me why this is the case? Why can't I specify a type constraint of System.Array
?
p.s.: While typing this out, I realized that I can accomplish what I originally wanted more easily, with a simple function like this:
void Print(System.Array a)
{
for (int i = 0; i < a.Length; i++)
{
Console.Write(a.GetValue(i));
}
}
Is this why there's a special rule for arrays in the compiler?
回答1:
The appropriate syntax to do what you want is this:
void Print<T>(T[] array)
{
for (int i = 0; i < array.Length; i++)
{
Console.Write(array[i]);
}
}
回答2:
If taken the question literally, it would be useless to have an Array
constraint. It's the same as it's useless to have a ValueType
constraint, as it actually doesn't check whether you use a value type as a generic argument, but whether the type you are passing is assignable to ValueType
.
So you can pass even Array
as the generic argument and it's OK.
What is actually useful is to have an array contraint allowing any type that derives from Array
, but not Array
itself:
void Print<TArr>(TArr t) where TArr : array //or [*] or other fancy syntax
Where T
can be []
, [,]
, [,,]
, [,,,]
, and so on. The only over non-generic Array
parameter is that we know the element type of the array.
Another way to solve this is to create a custom Array<T>
class with implicit operator overloads of T[]
, T[,]
, T[,,]
etc.
Edit:
There is no way to achieve this even in CIL (currently), because int[,]
and Array
don't differ in any interfaces or constructors. We need where T : Array but not Array itself
contraint.
来源:https://stackoverflow.com/questions/14795017/why-cant-system-array-be-a-type-constraint