【问题标题】:IEnumerable Cannot evaluate expression because the current thread is in a stack overflow stateIEnumerable 无法计算表达式,因为当前线程处于堆栈溢出状态
【发布时间】:2016-02-16 14:55:41
【问题描述】:

我正在编写一个应用程序,它接收一个 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
    }

【问题讨论】:

    标签: c# enumerable


    【解决方案1】:

    你看到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 方法将无济于事。更多内容,或许你想阅读How do I implement IEnumerable<T>

    【讨论】:

    • 请看我的编辑,我的类用私有类实现了这个 IEnumerable 那么如何将它转换成普通的 IEnumerable ?
    【解决方案2】:

    如果所有派生类都提供GetEnumerator() 方法,并且您对任何未来派生类都要求此方法没有问题,但您的基类无法有意义地定义一个,那么您将其标记为abstract

    public abstract IEnumerator<WiresharkFilePacket> GetEnumerator();
    

    这样就足以在您的基类上实现IEnumerable,您还不需要那里的完整定义。

    【讨论】:

    • 请看我的编辑,我的类用私有类实现了这个 IEnumerable 那么,如何将它转换为普通的 IEnumerable ?
    猜你喜欢
    • 2012-07-26
    • 2013-08-13
    • 2014-05-01
    • 2017-02-13
    • 1970-01-01
    • 2010-11-08
    • 1970-01-01
    • 2019-11-27
    • 1970-01-01
    相关资源
    最近更新 更多