Как вызвать Linq Take () над базовым классом IEnumerable?

Я пытаюсь: RandomBytes генерирует случайные байты (так что их можно перечислить). RandomNBytes то же самое, но случайные байты N (он расширяет RandomBytes). Итак, код:

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);
    }
}

Но есть проблема с base, VC выдает ошибку: использование ключевого слова "base" недопустимо в этом контексте. Как вызвать Take() через перечислимый базовый класс?

используйте this вместо base.

HimBromBeere 02.05.2018 13:53
base можно использовать только как способ доступа к определенной версии участника, он не относится к «базовой версии этого», вы должны использовать this для всех ссылок на экземпляр объекта, что вы пытаетесь делать здесь. К сожалению, это не очень хорошо сочетается с вашим кодом, поскольку он будет вызывать тот же GetEnumerator.
Lasse V. Karlsen 02.05.2018 13:55

Супер странно, return this.Take(Count).GetEnumerator(); работает

RandomB 02.05.2018 13:56
this (в этом контексте) позволяет вам получить доступ к методам (и свойствам и т. д.) или сам объект. base предназначен только для доступа к методам (и свойствам и т. д.).
mjwills 02.05.2018 13:58

@RandRandom да, я буду использовать его как генератор, комбинируя с Zip() с другой последовательностью (но конечной)

RandomB 02.05.2018 13:58

Вы знаете, что можете использовать random.NextBytes(array) вместо того, чтобы создавать для этого свои собственные классы.

Magnus 02.05.2018 14:00

@Magnus, но это загрязняет выделенный массив. Я предпочитаю генерировать сверх распределения, чтобы не съедать память

RandomB 02.05.2018 14:02

@ Paul-AG. Ваш return this.Take(Count).GetEnumerator();В самом деле работал, или он просто компилировался? Когда я его тестировал, он по-прежнему выдает тонны данных. Причина в том, что интерфейс IEnumerable реализуется базовым классом, а метод потомка GetEnumerator объявлен с помощью new, который не реализует метод интерфейса.

Lasse V. Karlsen 02.05.2018 14:11

Только что тестировал, только компилируется! Возникает исключение StackOverflowException!

RandomB 02.05.2018 14:13

С другой стороны, при вызове вашего нового GetEnumerator и последующем вызове .MoveNext() в перечислителе, как и ожидалось, возникает исключение переполнения стека.

Lasse V. Karlsen 02.05.2018 14:13

Как я уже сказал, переключение на this не согласуется с вашим запросом на добавление .Take, поскольку вам действительно нужно вызвать базовое перечислениебледный, а не базовое перечислениетор. Ваш единственный вариант, на мой взгляд, - это правильно реализовать вашего потомка GetEnumerator без использования LINQ.

Lasse V. Karlsen 02.05.2018 14:14

@ LasseVågsætherKarlsen, ты супер прав. Этот вариант работает!

RandomB 02.05.2018 14:18

Вот пример - gist.github.com/lassevk/b78847a6cddde43a8cd4f783d5fb9160 - не может прямо сейчас написать правильный ответ, но любой, кто хочет, может просто скопировать и переписать этот код и сделать его своим собственным ответом.

Lasse V. Karlsen 02.05.2018 14:22
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
14
79
1

Ответы 1

Я бы сделал это так:

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
    }
}

Другие вопросы по теме