public Triangle(List<Vertex> vertices) {
this._values = vertices;
}
我尝试使用值列表初始化对象,对象只是引用了我的对象而不是从列表中获取值。如果我不放弃我作为参数传递的列表并稍后使用它来做其他事情,比如用相同的值初始化其他东西,或者如果我决定清除它并填充新的值,我显然会破坏我的{的状态{1}}对象不知道它。
我的第一反应是在构造函数中“修复bug”,但后来我开始思考它是否真的应该如此。涵盖这类事情的良好做法是什么?一般来说,我应该如何看待采用值列表的构造函数/ init方法?他们应该完好无损吗?我是否允许重复使用列表,并在导致错误时出现错误?
我的意思是,我显然可以这样做:
Triangle
但不应该由var triangle = new Triangle(new List<Vertex>(vertices));
类的创建者完成吗?
我想知道一些指导方针。感谢。
答案 0 :(得分:4)
是的,接收类(Triangle)应该复制,除非设计是故意共享 List。
分享可能很有用,但却是例外。我不认为Triangle想要用其他东西分享它的顶点列表。
请注意,它仍然可以共享顶点(元素)。
答案 1 :(得分:2)
我个人同意Henk;你应该创建一个副本。
/// <summary>
/// Initialises a new instance of the <see cref="Triangle"/> class that
/// contains elements copied from the specified collection.
/// </summary>
/// <param name="vertices">
/// The collection of vertices whose elements are to be copied.
/// </param>
public Triangle(IEnumerable<Vertex> vertices)
{
this.Vertices = new List<Vertex>(vertices);
}
无论您选择什么,只需确保记录下来,以便消费者了解所期望的行为。
因此消费者知道他们可以安全地拨打new Triangle(vertices)
。
答案 2 :(得分:2)
C#是一种按值传递的语言,但由于列表是引用类型,因此它按值传递其引用。如您所述,这意味着您将列表的共享引用传递给类的构造函数。在代码中的任何位置进行的修改都会影响相同的列表。
这取决于您的班级所期望的行为是什么。如果要进行深层复制,最简单的方法是在构造函数中分配一个新列表,并将IEnumerable引用传递给列表的构造函数。
如果您想分享参考资料,这是一个完全有效的解决方案,只需确保您正确记录您的课程(或为您的课程命名)。
答案 3 :(得分:1)
在这种情况下,将List对象传递给构造函数将被视为设计不佳。也许更好的解决方案是使用方法
class Triangle
{
List<Vertex> Vertices = new List<Vertex>(); // The triangle owns the vertex collection...
public void SetVertices(IEnumerable<Vertex> vertices)
{
this.Vertices.Clear();
this.Vertices.AddRange(vertices);
}
}
答案 4 :(得分:1)
我会说这是一个文档问题。文档,即使它只是intellisense文档,应该说明是否使用值给定列表初始化类,或者它是否将直接使用给定列表。给定任何可变引用类型,这是一个有效的问题,应该记录在案。
缺乏适当的文档,我会说这取决于你,这个班级的消费者,保护自己免受无证件的行为。你有两个选择:
找出应该告诉你的文档。您可以使用Reflector或简单实验来确定代码对您传递的可变对象执行的操作。
保护自己免受班级的行为,无论它是什么。如果一个类采用可变对象,则不要重用该对象。这样,即使班级的行为在以后发生变化,您也是安全的。
在您的具体情况下,我不认为Triangle
类是错误的。它的构造函数可以采用IEnumerable<Vertex>
1 并使用这些值初始化成员List<Vertex>
,相反,它的设计者选择了{{ 1}}直接使用它。这可能是基于绩效的决定。
1 为了完整,如果有点迂腐,我应该提一下,即使花了List<Vertex>
,你仍然会遇到同样的问题。该类仍然可以存储和重用对该对象的引用,因此对稍后对列表所做的更改很敏感。但是,在这种情况下,我会认为要打破IEnumerable<Vertex>
类。除了少数例外情况,公约规定采用Triangle
的方法或构造函数将使用它一次然后丢弃它。
答案 5 :(得分:0)