【问题标题】:NullReferenceException when trying to populate an empty instance of a custom class with a struct尝试使用结构填充自定义类的空实例时出现 NullReferenceException
【发布时间】:2013-06-06 14:01:51
【问题描述】:

我创建了一个自定义结构和一个类。结构是 3D 空间中的点:

public struct Point3D
{
    //fields
    private static Point3D center = new Point3D(0,0,0);

    //properties
    public int X { get; set; }
    public int Y { get; set; }
    public int Z { get; set; }
    public static Point3D Center { get { return center; } }

    //constructors
    public Point3D(int x, int y, int z) : this()
    {
        this.X = x;
        this.Y = y;
        this.Z = z;
    }

    public override string ToString() { return string.Format("({0}; {1}; {2})", this.X, this.Y, this.Z); }
}

自定义类是应该存储点的路径:

public class Path
{
    private List<Point3D> storedPoints = new List<Point3D>();

    public List<Point3D> StoredPoints { get; set; }

    public void AddPoint(Point3D point) { this.StoredPoints.Add(point); }

    public void DeletePointAt(int index) { this.StoredPoints.RemoveAt(index); }

    public void ClearPath() { this.StoredPoints.Clear(); }

    public override string ToString()
    {
        StringBuilder sb = new StringBuilder();
        foreach (var item in this.StoredPoints)
        {
            sb.Append(item);
            sb.Append(System.Environment.NewLine);
        }
        return sb.ToString();
    }
}

我没有为路径类创建构造函数,因为我总是希望有一个实例,其中包含一个空列表 List\。但是,当我运行程序时,我得到 NullReferenceException。这是main方法的代码:

    static void Main(string[] args)
    {
        Point3D point1 = new Point3D(-2, -4, -10);
        Point3D point2 = new Point3D(6, 7, 8);
        Path path1 = new Path();
        path1.AddPoint(point1);
        path1.AddPoint(point2);
        path1.AddPoint(new Point3D(2, 4, 6));
        path1.AddPoint(new Point3D(-9, 12, 6));
        Console.WriteLine(path1);
    }

当我尝试添加第一点时出现错误。在调试器中,我看到 Path 对象在添加第一个点之前的值为 null,但是如何在无需编写构造函数的情况下克服这个问题,将至少一个点作为参数,即创建一个空路径。

【问题讨论】:

  • 感谢大家。只是一个子问题。如果我完全删除私有字段 List storedPoints 并留下自动属性 ​​public List StoredPoints { get;放; }?为什么这不起作用?

标签: c# .net class struct nullreferenceexception


【解决方案1】:

您的 StoredPoints 属性是单独的且未初始化。您的意图可能是它会获取/设置您的私人storedPoints 字段。修改 StoredPoints 的 get/set 函数来获取/设置你的私有字段,你就会解决你的问题。

public List<Point3D> StoredPoints 
{ 
  get
  {
    return storedPoints;
  }
}

编辑:

如果您消除了storedPoints 字段,但仍然不需要构造函数,则可以执行以下操作:

public void AddPoint(Point3D point) 
{ 
  if (this.StoredPoints == null)
    this.StoredPoints = new List<Point3D>();
  this.StoredPoints.Add(point); 
}

这称为延迟初始化。但是,上述实现不是线程安全的。如果你保证是单线程的,那应该没问题。您可能希望将类似的初始化放在StoredPoints 的其他修饰符中。每当直接从类外部访问它时,您还需要检查 StoredPoints 是否为 null。

编辑:

我没有为路径类创建构造函数,因为我总是希望有一个实例,其中包含一个空列表 List\。

一个与另一个无关。你可以有一个构造函数而不初始化你的列表。

还有一点要记住:拥有一个空的StoredPoints 属性实际上与一个空的StoredPoints 属性有什么不同吗?如果不是,那么安全并将StoredPoints 初始化为一个空列表。

【讨论】:

  • 关于线程安全,List&lt;T&gt; 类型也不是线程安全的,所以即使他在构造函数中初始化它,在多线程场景中事情仍然会崩溃(他应该从System.Collections.Concurrent变成一个集合。
  • 感谢两位的完美解释。我仍然不明白的部分是为什么我必须初始化它,如果我将它初始化为一个空列表,默认情况下它的值为 null。在这两种情况下,它的值为 null,但在第二种情况下,它是显式初始化的?但我想这是我需要进一步努力的事情,因为我是新手。
  • 默认情况下,您的属性值为null。如果您使用new List&lt;Point3D&gt;() 对其进行初始化,它将不是null,而是一个有效的空列表。不要混淆“无列表”(即为空)和“空列表”(即存在但为空的列表)。
【解决方案2】:

您有两个不相关的成员 storedPointsStoredPoints

你应该明确写出StoredPoints的getter,让它返回storedPoints

(另外,您创建的结构是可变结构。这被许多人认为是危险的。)

【讨论】:

  • 因为它的默认值为空。您必须在某个地方(通常在构造函数中)对其进行初始化。
【解决方案3】:
public List<Point3D> StoredPoints { get; set; }

当您调用AddPoints 时,您正在尝试访问尚未初始化的属性。在使用StoredPoints 属性之前,您必须这样做

StoredPoints = new List<Point3D>();

【讨论】:

    猜你喜欢
    • 2013-12-31
    • 1970-01-01
    • 1970-01-01
    • 2012-07-12
    • 2017-08-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多