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?
If taken the question literally, it would be useless to have an
Array
constraint. It's the same as it's useless to have aValueType
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 toValueType
.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 notArray
itself:Where
T
can be[]
,[,]
,[,,]
,[,,,]
, and so on. The only over non-genericArray
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 ofT[]
,T[,]
,T[,,]
etc.Edit:
There is no way to achieve this even in CIL (currently), because
int[,]
andArray
don't differ in any interfaces or constructors. We needwhere T : Array but not Array itself
contraint.The appropriate syntax to do what you want is this: