A for loop like
for (T i = a; i < b; i++)
{
// do something
}
looks quite normal.
On a second glance, you'll notice T
instead of a primitive datatype - a generic type.
Still shouldn't be a problem, you will think. T
could be anything, not limited to a number - a string, even a complex object, as long as it is comparable and enumerable (i.e. you need to apply the constraint where T: IEnumerable, IComparable
to it).
NOTE:
I am not interested in restricting a generic for loop to numbers only, it should be applicable to all kind of data types.
Because of the fact that it is not limited to numbers, and since Eric gave an answer which is applicable to any type of object this question is NOT a duplicate of the question "Is there a constraint that restricts my generic method to numeric types?"
It seems to be not so easy to remove a mistakenly applied duplicate flag in Stackoverflow, i.e. despite of my explanations the duplicate box is still there. The review queues seem to be not effective enough ...
But back to this question: I thought the same way, then I started playing around a bit with that and tried to write something like
IEnumerable<T> MyFor<T>(T a, T b)
where T: IEnumerable, IComparable
{
for (T i = a; i < b; i++)
{
yield return i;
}
}
to implement a generator which can be used for double, int, strings ...
which would be a generic for-loop. The constraints IEnumerable
and IComparable
are just there to tell the compiler that elements of this type can be enumerated and compared (because of the i < b
expression in the for
loop and the increment), and if C# would have that, INumeric would be a quite useful constraint, too (which would then implicitly be comparable and enumerable of course).
To my surprise, this example doesn't compile, it generates the following errors:
CS0019: Operator '<' cannot be applied to operands of type 'T' and 'T'
CS0023: Operator '++' cannot be applied to operand of type 'T'
The reason seems to be that there is no constraint for numerics, but there doesn't seem to be any practical solution available, as some of the answers here are explaining.
Note: A similar (non-generic) version of this does compile:
IEnumerable<double> MyFor(double a, double b)
{
for (var i = a; i < b; i++)
{
yield return i;
}
}
IEnumerable<int> MyFor(int a, int b)
{
for (var i = a; i < b; i++)
{
yield return i;
}
}
IEnumerable<string> MyFor(string a, string b)
{
for (string i = a; i.Length < b.Length; i = i + a)
{
yield return i;
}
}
If you have it overloaded like shown above, you can invoke it like
var intNumbers = MyFor((int)1, 10);
var doubleNumbers = MyFor((double)1, 10);
var stringFor = MyFor("*", "abcde");
and due to the signature of the parameters the correct version is chosen. But of course, this is not elegant because you're duplicating code just for the sake of different data types used.
In essence, in order to make the code more elegant and less redundant, the questions are:
1. Is it possible to write a generic function as the one which can be invoked like
var intNumbers = MyFor<int>(1, 10);
var doubleNumbers = MyFor<double>(1, 10);
var stringFor = MyFor<string>("*", "abcde");
as shown in my first example?
(I am not sure about the correct constraint, I thought that where T: IEnumerable, IComparable
would do because you need to compare i < b
and you need to iterate to the next bigger item).
2. a) How can I write a generic constraint that will allow me to increment and compare variables of type T
?
2. b) If there's no such constraint, is there a way to simulate a for-loop with generic arguments?
3. How can a for-loop be made generic?