IEnumerable Не удается оценить выражение, поскольку текущий поток находится в состоянии переполнения стека

Я пишу приложение, которое берет файл Wireshark (Pcap, Snopp, Pcapng...), открывает его и читает все пакеты.

Мой базовый класс:

public abstract class WiresharkFile
{
   ...
}

И все подклассы реализованы IEnumerable:

public class Libpcap : WiresharkFile, IDisposable, IEnumerable<WiresharkFilePacket>
{
    ....
}

Теперь, когда я создаю объект, мой код распознает его автоматически, а затем создает текущий тип object, например:

wiresharkFile = new Libpcap(file);

И затем, когда я хочу перебрать свой файл и прочитать пакеты:

foreach (var packet in wiresharkFile)
{
   ...
}

Я получаю эту ошибку:

Оператор foreach не может работать с переменными типа WiresharkFile, поскольку WiresharkFile не содержит общедоступного определения для GetEnumerator.

Поэтому я добавил эту функцию в базовый класс WiresharkFile:

public IEnumerator<WiresharkFilePacket> GetEnumerator()
{
    return GetEnumerator();
}

И теперь я получаю эту ошибку StackOverflowException:

Невозможно оценить выражение, так как текущий поток находится в состоянии переполнения стека.

Изменить

public class Libpcap : WiresharkFile, IDisposable, IEnumerable<WiresharkFilePacket>
{
    private BinaryReader binaryReader;
    private Version version;
    private uint snaplen;
    private int thiszone;
    private uint sigfigs;
    private LibpcapLinkType linktype;
    private long basePos;
    private bool byteSwap;
    private static uint MAGIC = 0xa1b2c3d4;
    private static uint MAGIC_ENDIAN = 0xd4c3b2a1;

    public Libpcap(string path) : this(new FileStream(path, FileMode.Open, FileAccess.Read))
    {
        FileName = path;
        binaryReader = new BinaryReader(new FileStream(path, FileMode.Open, FileAccess.Read));
    }        

    public void Close()
    {
        binaryReader.Close();
    }

    public enum LibpcapLinkType
    {
        Null,
        Ethernet,
        ExpEthernet,
        AX25,
        ProNet,
        Chaos,
        TokenRing,
        ArcNet,
        Slip,
        Ppp,
        Fddi
    }

    public Libpcap(Stream s)
    {
        binaryReader = new BinaryReader(s);
        uint magic = binaryReader.ReadUInt32();

        ushort major = binaryReader.ReadUInt16();
        ushort minor = binaryReader.ReadUInt16();

        thiszone = binaryReader.ReadInt32();
        sigfigs = binaryReader.ReadUInt32();
        snaplen = binaryReader.ReadUInt32();
        uint ltype = binaryReader.ReadUInt32();

        if (byteSwap)
        {
            major = ByteSwap.Swap(major);
            minor = ByteSwap.Swap(minor);
            thiszone = ByteSwap.Swap(thiszone);
            snaplen = ByteSwap.Swap(snaplen);
            ltype = ByteSwap.Swap(ltype);
        }

        version = new Version(major, minor);
        linktype = (LibpcapLinkType)((int)ltype);
        basePos = binaryReader.BaseStream.Position;

        protected override WiresharkFilePacket ReadPacket()
        {
            if (binaryReader.BaseStream.Position < binaryReader.BaseStream.Length)
            {
                int secs = binaryReader.ReadInt32();
                int usecs = binaryReader.ReadInt32();
                uint caplen = binaryReader.ReadUInt32();
                uint len = binaryReader.ReadUInt32();
                if (byteSwap)
                {
                    secs = ByteSwap.Swap(secs);
                    usecs = ByteSwap.Swap(usecs);
                    caplen = ByteSwap.Swap(caplen);
                    len = ByteSwap.Swap(len);
                }

                DateTime timeStamp = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds((Double)secs).AddMilliseconds((Double)usecs / 1000);
                byte[] data = binaryReader.ReadBytes((int)caplen);

                return new WiresharkFilePacket(timeStamp, data);
            }
            else
                return null;
        }

        public Version Version
        {
            get
            {
                return version;
            }
        }

        public uint MaximumCaptureLength
        {
            get
            {
                return snaplen;
            }
        }

        public int TimezoneOffset
        {
            get
            {
                return thiszone;
            }
        }

        public uint SignificantFigures
        {
            get
            {
                return sigfigs;
            }
        }

        public LibpcapLinkType LinkType
        {
            get
            {
                return linktype;
            }
        }

        public void Rewind()
        {
            binaryReader.BaseStream.Position = basePos;
        }

        public override string ToString()
        {
            string endianness;

            if (BitConverter.IsLittleEndian)
            {
                if (byteSwap)
                    endianness = "Big";
                else
                    endianness = "Little";
            }
            else
            {
                if (byteSwap)
                    endianness = "Little";
                else
                    endianness = "Big";
            }

            return String.Format("{0}-endian {1} capture, pcap version {2}", endianness, linktype.ToString(), version.ToString());
        }

        public void Dispose()
        {
            binaryReader.Close();
        }

        public class PacketEnumerator : IEnumerator<WiresharkFilePacket>
        {
            private Libpcap file;
            private WiresharkFilePacket currentPacket = null;

            public PacketEnumerator(Libpcap file)
            {
                this.file = file;
            }

            #region IEnumerator<PcapPacket> Members

            public WiresharkFilePacket Current
            {
                get { return currentPacket; }
            }

            #endregion

            #region IDisposable Members

            public void Dispose()
            {
            }

            #endregion

            #region IEnumerator Members

            object System.Collections.IEnumerator.Current
            {
                get { return currentPacket; }
            }

            public bool MoveNext()
            {
                currentPacket = file.ReadPacket();
                return currentPacket != null;
            }

            public void Reset()
            {
                file.Rewind();
            }

            #endregion
        }

        #region IEnumerable<PcapPacket> Members

        public IEnumerator<WiresharkFilePacket> GetEnumerator()
        {
            return new PacketEnumerator(this);
        }

        #endregion

        #region IEnumerable Members

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return new PacketEnumerator(this);
        }

        #endregion
    }

person david hol    schedule 15.11.2015    source источник


Ответы (2)


Вы видите StackOverflowException, потому что звоните сами себе

public IEnumerator<WiresharkFilePacket> GetEnumerator()
{
    return GetEnumerator();
}

Вам нужно правильно реализовать итератор, чтобы это работало. Например:

public IEnumerator<WiresharkFilePacket> GetEnumerator()
{
    for (int i = 0; i < 10; i++)
        yield return new WiresharkFilePacket();
}

Ваш WiresharkFile должен иметь некоторую внутреннюю коллекцию, которую он может перебирать. Будь то пакеты, которые вы анализируете из pcap и возвращаете. Простое создание метода GetEnumerator ничего не даст. Для получения дополнительной информации, возможно, вы захотите прочитать Как мне реализовать IEnumerable‹T›

person Yuval Itzchakov    schedule 15.11.2015
comment
Пожалуйста, посмотрите мое редактирование, мой класс реализует этот IEnumerable с частным классом, так как преобразовать его в обычный IEnumerable? - person david hol; 15.11.2015

Если все производные классы предоставляют метод GetEnumerator(), и у вас нет проблем с требованием этого для каких-либо будущих производных классов, но ваш базовый класс не может осмысленно определить его, тогда вы помечаете его abstract.

public abstract IEnumerator<WiresharkFilePacket> GetEnumerator();

Таким образом, достаточно реализовать IEnumerable в вашем базовом классе, вам пока не нужно полное определение.

person Community    schedule 15.11.2015
comment
Пожалуйста, посмотрите мое редактирование, мой класс реализует этот IEnumerable с частным классом, так как преобразовать его в обычный IEnumerable? - person david hol; 15.11.2015