3

Is this a clean and correct way to generate a list of consecutive uints?

The cast looks kind of ugly, but I'm a beginner...might be there is a method without casting around?

public class Test
{
    static readonly IEnumerable<uint> AvailableChannels 
         = (IEnumerable<uint>)Enumerable.Range(1,1000);
}
Ronald McBean
  • 1,417
  • 2
  • 14
  • 27
  • Did you even try it? This throws an exception: http://ideone.com/dGkrvr – Henrik Dec 10 '12 at 14:01
  • @Henrik: Yes I did try, a lot.... But this is a abbreviated example, that I did not compile. Apologies if there are compile errors, but I think you get my point. – Ronald McBean Dec 10 '12 at 14:04

2 Answers2

9
static readonly IEnumerable<uint> AvailableChannels 
     = Enumerable.Range(1,1000)
       .Select(i => (uint)i)
       .ToList();

It's still a cast though ...

EDIT
The .ToList() is so the full list doesn't need to be recreated every time you loop over it. (OK, a 1000 uints isn't much, but it's the principle of it - if they were classes you would create new ones every time and get unexpected results, like lost changes)

EDIT2
The Cast<uint>() doesn't work at runtime ("Specified cast is not valid"). Changed to a .Select to perform the cast.

Hans Kesting
  • 38,117
  • 9
  • 79
  • 111
  • So the cast travelled from front to back, but I have an additional `ToList()` call. What is the improvement to the solution in my answer? I just want to understand it! – Ronald McBean Dec 10 '12 at 13:59
  • I'd be interested to know whether this resulted in more or less overhead than casting the sequence in one go, but aside from that, this is still using casting. (Edit: Assumed the as-one cast worked through covariance. Maybe not.) – Rawling Dec 10 '12 at 14:00
  • The solution compiles but throws a runtime exception "specified cast is not valid" using Visual Studio 2010. Any ideas why? – Ronald McBean Dec 12 '12 at 12:45
  • @RonaldMcBean - I didn't expect that. Corrected sample code and tested it. – Hans Kesting Dec 12 '12 at 12:52
  • 1
    Only what now if I need numbers bigger than `int`? That's the whole reason for using a `uint` sometimes. – Tvde1 Nov 27 '18 at 11:06
  • @Tvde1 [Enumerable.Range](https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.range) only delivers `int`s (it throws an exception if it would return values over `int.MaxValue`). You would have to create your own version of it to generate `uint` directly or even `long` – Hans Kesting Nov 27 '18 at 11:26
8

You can write your own enumerable method :

public static IEnumerable<uint> Foo(
    uint startValue =0, 
    uint maxValue = uint.MaxValue
    )
{
    uint index = startValue;
    while(index < maxValue) {
        yield return index++;
    }
}

public static void Main()
{
    var myUints = Foo().Take(100);
    var myUints2 = Foo(startValue:0, maxValue:1000);
    var myUints3 = Foo(0, 1000);
    foreach(uint x in myUints) {
        Console.WriteLine(x);
    }
}

A side note: If performance is a critical point in your application, you may read this question : Why is Enumerable.Range faster than a direct yield loop? (especially the answer marked as the answer)

Community
  • 1
  • 1
Steve B
  • 36,818
  • 21
  • 101
  • 174
  • You are right. I've added a `maxValue` parameter to make this more explicit, even if the `Take` extension method do the job – Steve B Dec 10 '12 at 14:01
  • C'mon man, you're most of the way there, just add a `start` value :D – Rawling Dec 10 '12 at 14:01
  • 1
    @RonaldMcBean: the complexity is hidden in the method **once**. All consumer code don't need to worry about the implementation. Moreover, you don't have to play with the default parameters' value. You can ask to always pass upper and lower bounds of your range, depending on the usage of the method. – Steve B Dec 10 '12 at 14:03