C# - Odd Null参考测试期间的异常,为什么会发生这种情况?

时间:2016-10-11 18:29:26

标签: c# visual-studio if-statement nullreferenceexception

这引用了我似乎已被放弃的last question。如果您使用C#和MS VS 2015,我会遇到一个奇怪的“错误”。要重现错误,请按照以下步骤操作:

  1. 打开控制台应用程序项目并复制下面的粘贴代码。
  2. 在此处设置断点: enter image description here
  3. 首先运行代码过去的断点,它的工作原理! :d
  4. 然后再次运行代码,但这次在断点处停止,并将执行语句游标从这里拖到if语句中: enter image description here 到这里: enter image description here
  5. 点击Continue并抛出NRE异常。为什么会这样?只有我吗?这方面的技术探索是什么?

    CODE:

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace testapp
    {
        class Program
        {
            static void Main(string[] args)
            {
                FILECollection randomCollection = new FILECollection();
                // Fill with junk test data:
                for(int i = 0; i<10; i++)
                {
                    FILE junkfile = new FILE() { fileName = i.ToString(), folderName = i.ToString(), fileHashDigest = new byte[1] };
                    randomCollection.Add(junkfile);
                }
    
                if (true)
                {
                    Console.WriteLine("testing this weird exception issue...");
                    FILE test;
                    test = new FILE();
                    test.fileName = "3";
                    test.folderName = "3";
                    test.fileHashDigest = new byte[1];
    
                    FILE exists = randomCollection.Where(f => f.fileName == test.fileName &&
                                                  f.fileHashDigest.SequenceEqual(test.fileHashDigest)).First();
                }
            }
        }
    
    
        public class FILE
        {
            public FILE() { _fileName = "";}
            private string _fileName;
            public string fileName
            {
    
                get
                {
                        if (false)
                            return this._fileName.ToUpper();
                        else
                            return this._fileName;
                }
                set
                {
    
                        if (false)
                            this._fileName = value.ToUpper();
                        else
                            this._fileName = value;
                }
            }
            public string folderName { get; set; }
            public byte[] fileHashDigest { get; set; }
        }
    
        public class FILECollection : IEnumerable<FILE>, ICollection<FILE>
        {
            private HashSet<FILE> svgHash;
            private static List<FILE> PreallocationList;
            public string FileName = "N/A";
    
            /// <summary>
            /// Default Constructor, will not 
            /// preallocate memory.
            /// </summary>
            /// <param name="PreallocationSize"></param>
            public FILECollection()
            {
                this.svgHash = new HashSet<FILE>();
                this.svgHash.Clear();
            }
    
            /// <summary>
            /// Overload Constructor Preallocates
            /// memory to be used for the new 
            /// FILE Collection.
            /// </summary>
            public FILECollection(int PreallocationSize, string fileName = "N/A", int fileHashDigestSize = 32)
            {
                FileName = fileName;
                PreallocationList = new List<FILE>(PreallocationSize);
                for (int i = 0; i <= PreallocationSize; i++)
                {
                    byte[] buffer = new byte[fileHashDigestSize];
                    FILE preallocationSVG = new FILE()
                    {
                        fileName = "",
                        folderName = "",
                        fileHashDigest = buffer
                    };
                    PreallocationList.Add(preallocationSVG);
                }
                this.svgHash = new HashSet<FILE>(PreallocationList);
                this.svgHash.Clear(); // Capacity remains unchanged until a call to TrimExcess is made.
            }
    
            /// <summary>
            /// Add an FILE file to 
            /// the FILE Collection.
            /// </summary>
            /// <param name="svg"></param>
            public void Add(FILE svg)
            {
                this.svgHash.Add(svg);
            }
    
            /// <summary>
            /// Removes all elements 
            /// from the FILE Collection
            /// </summary>
            public void Clear()
            {
                svgHash.Clear();
            }
    
    
            /// <summary>
            /// Determine if the FILE collection
            /// contains the EXACT FILE file, folder, 
            /// and byte[] sequence. This guarantees 
            /// that the collection contains the EXACT
            /// file you are looking for.
            /// </summary>
            /// <param name="item"></param>
            /// <returns></returns>
            public bool Contains(FILE item)
            {
                return svgHash.Any(f => f.fileHashDigest.SequenceEqual(item.fileHashDigest) &&
                                        f.fileName == item.fileName &&
                                        f.folderName == item.folderName);
            }
    
            /// <summary>
            /// Determine if the FILE collection 
            /// contains the same file and folder name, 
            /// byte[] sequence is not compared. The file and folder
            /// name may be the same but this does not guarantee the 
            /// file contents are exactly the same. Use Contains() instead.
            /// </summary>
            /// <param name="item"></param>
            /// <returns></returns>
            public bool ContainsPartially(FILE item)
            {
                return svgHash.Any(f => f.fileName == item.fileName &&
                                        f.folderName == item.folderName);
            }
    
            /// <summary>
            /// Returns the total number
            /// of FILE files in the Collection.
            /// </summary>
            public int Count
            { get { return svgHash.Count(); } }
    
            public bool IsReadOnly
            { get { return true; } }
    
            public void CopyTo(FILE[] array, int arrayIndex)
            {
                svgHash.CopyTo(array, arrayIndex);
            }
    
            public bool Remove(FILE item)
            {
                return svgHash.Remove(item);
            }
    
            public IEnumerator<FILE> GetEnumerator()
            {
                return svgHash.GetEnumerator();
            }
    
            IEnumerator IEnumerable.GetEnumerator()
            {
                return svgHash.GetEnumerator();
            }
        }
    }
    

    我认为要么以非常错误的方式进行调试,要么微软应该看看这个。这就像未来的代码破坏了当前的代码......这是不可能的!

    enter image description here

1 个答案:

答案 0 :(得分:4)

好的,这是我最好的猜测......

首先,正如我在评论中提到的,如果您注释掉FILE exists = randomCollection.Where(f => f.fileName == test.fileName && f.fileHashDigest.SequenceEqual(test.fileHashDigest)).First()‌​;

,则不会发生例外情况

其次,我注意到可以使用以下代码重现相同的行为:

if (true)
{
    object o;
    o = new object();
    Func<bool> m = () => o == null;
}

即。原因似乎与lambda表达式中使用的变量有关。因此,查看ILSpy上面的相同代码片段,我得到以下内容:

Program.<>c__DisplayClass0_0 <>c__DisplayClass0_ = new Program.<>c__DisplayClass0_0();
<>c__DisplayClass0_.o = new object();
Func<bool> func = new Func<bool>(<>c__DisplayClass0_.<Main>b__0);

所以我最好的猜测是NullReferenceException指的是<>c__DisplayClass0_ intance是null - 因此我倾向于相信踩过if(true)实际上跳过了<>c__DisplayClass0_实例化的第一行