Я пытаюсь: 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()
через перечислимый базовый класс?
base
можно использовать только как способ доступа к определенной версии участника, он не относится к «базовой версии этого», вы должны использовать this
для всех ссылок на экземпляр объекта, что вы пытаетесь делать здесь. К сожалению, это не очень хорошо сочетается с вашим кодом, поскольку он будет вызывать тот же GetEnumerator
.
Супер странно, return this.Take(Count).GetEnumerator();
работает
this
(в этом контексте) позволяет вам получить доступ к методам (и свойствам и т. д.) или сам объект. base
предназначен только для доступа к методам (и свойствам и т. д.).
@RandRandom да, я буду использовать его как генератор, комбинируя с Zip()
с другой последовательностью (но конечной)
Вы знаете, что можете использовать random.NextBytes(array)
вместо того, чтобы создавать для этого свои собственные классы.
@Magnus, но это загрязняет выделенный массив. Я предпочитаю генерировать сверх распределения, чтобы не съедать память
Возможный дубликат Как получить экземпляр базового класса из производного класса
@ Paul-AG. Ваш return this.Take(Count).GetEnumerator();
В самом деле работал, или он просто компилировался? Когда я его тестировал, он по-прежнему выдает тонны данных. Причина в том, что интерфейс IEnumerable
реализуется базовым классом, а метод потомка GetEnumerator
объявлен с помощью new
, который не реализует метод интерфейса.
Только что тестировал, только компилируется! Возникает исключение StackOverflowException!
С другой стороны, при вызове вашего нового GetEnumerator
и последующем вызове .MoveNext()
в перечислителе, как и ожидалось, возникает исключение переполнения стека.
Как я уже сказал, переключение на this
не согласуется с вашим запросом на добавление .Take
, поскольку вам действительно нужно вызвать базовое перечислениебледный, а не базовое перечислениетор. Ваш единственный вариант, на мой взгляд, - это правильно реализовать вашего потомка GetEnumerator
без использования LINQ.
@ LasseVågsætherKarlsen, ты супер прав. Этот вариант работает!
Вот пример - gist.github.com/lassevk/b78847a6cddde43a8cd4f783d5fb9160 - не может прямо сейчас написать правильный ответ, но любой, кто хочет, может просто скопировать и переписать этот код и сделать его своим собственным ответом.
Я бы сделал это так:
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
}
}
используйте
this
вместоbase
.