0

I'm trying: RandomBytes generates random bytes (so, it's enumerable). RandomNBytes is the same but N random bytes (it extends RandomBytes). So, code is:

class RandomBytes : IEnumerable<byte>, IEnumerable {
    public IEnumerator<byte> GetEnumerator() {
        var rnd = new Random();
        while (true) {
            yield return (byte)rnd.Next(0, 255);
        }
    }

    IEnumerator IEnumerable.GetEnumerator() {
        return this.GetEnumerator();
    }
}

class RandomNBytes : RandomBytes {
    readonly UInt64 Count;

    RandomNBytes (UInt64 count) {
        Count = count;
    }

    public new IEnumerator<byte> GetEnumerator() {
        return ((IEnumerable<byte>)base).Take(Count);
    }
}

But there is a problem with base, VC raises error: Use of keyword "base" is not valid in this context. How to call Take() over base-class enumerable?

RandomB
  • 3,367
  • 19
  • 30
  • 4
    use `this` instead of `base`. – MakePeaceGreatAgain May 02 '18 at 11:53
  • 3
    `base` can only be used as a way of getting to a specific version of a member, it does not refer to "base version of this", you have to use `this` for all references to the *object instance*, which is what you're trying to do here. Unfortunately this doesn't mesh with your code all that well, since it will call the same `GetEnumerator`. – Lasse V. Karlsen May 02 '18 at 11:55
  • 1
    Super strange, `return this.Take(Count).GetEnumerator();` works – RandomB May 02 '18 at 11:56
  • 2
    `this` (in this context) allows you to access methods (and properties etc) **or the object itself**. `base` is only to access methods (and properties etc). – mjwills May 02 '18 at 11:58
  • @RandRandom yes, I will use it as generator, combinind with `Zip()` with another sequence (but finite) – RandomB May 02 '18 at 11:58
  • You know you can use `random.NextBytes(array)` instead of making your own classes for this. – Magnus May 02 '18 at 12:00
  • @Magnus but this pollute allocated array. I prefer generating over allocation to avoid memory eat – RandomB May 02 '18 at 12:02
  • Possible duplicate of [How to Get Base Class Instance from a Derived Class](https://stackoverflow.com/questions/19243057/how-to-get-base-class-instance-from-a-derived-class) – mjwills May 02 '18 at 12:02
  • @Paul-AG Did your `return this.Take(Count).GetEnumerator();` **really** work, or did it just compile? It still produces tons of data when I tested it. The reason is that the `IEnumerable` interface is implemented by the base class, and the `GetEnumerator` method of the descendant is declared with `new`, which doesn't implement the method of the interface. – Lasse V. Karlsen May 02 '18 at 12:11
  • I just tested it, it is compiled only! StackOverflowException is raising! – RandomB May 02 '18 at 12:13
  • 1
    On the other hand, actually calling your new `GetEnumerator`, then calling `.MoveNext()` on the enumerator ends up with a stack overflow exception, as expected. – Lasse V. Karlsen May 02 '18 at 12:13
  • 1
    As I said, switching to `this` doesn't mesh with your request to append `.Take` as you actually need to call the base enumera**ble**, not the base enumera**tor**. Your only option the way I see it is to actually implement your descendant `GetEnumerator` properly, without using LINQ. – Lasse V. Karlsen May 02 '18 at 12:14
  • @LasseVågsætherKarlsen you are super right. This variant works! – RandomB May 02 '18 at 12:18
  • 1
    Here's an example - https://gist.github.com/lassevk/b78847a6cddde43a8cd4f783d5fb9160 - not able to write up a proper answer right now but anyone that wants to can just copy and rewrite that code and make it their own answer. – Lasse V. Karlsen May 02 '18 at 12:22

1 Answers1

1

I would do it like this:

public class RandomBytes : IEnumerable<byte>, IEnumerable
{
    public IEnumerator<byte> GetEnumerator()
    {
        //used null, but could also drop the nullable and just pass ulong.MaxValue into the method
        return GetEnumerator(null);
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        return this.GetEnumerator();
    }

    //extracted the "main" method to a seperate method that takes a count
    protected IEnumerator<byte> GetEnumerator(ulong? count)
    {
        //use ulong.MaxValue when null gets passed, 
        //what ever you are doing with this code 18,446,744,073,709,551,615 iterations should be enough
        var c = count ?? ulong.MaxValue; 

        var rnd = new Random();
        for (ulong i = 0; i < c; i++)
            yield return (byte)rnd.Next(0, 255);
    }
}

public class RandomNBytes : RandomBytes
{
    readonly ulong Count;

    public RandomNBytes(ulong count)
    {
        Count = count;
    }

    public new IEnumerator<byte> GetEnumerator()
    {
        return GetEnumerator(Count); //call the protected method
    }
}
Rand Random
  • 7,300
  • 10
  • 40
  • 88