分配引用类型属性时的最佳实践

Best practice when assigning reference type properties

我只是想知道在分配引用类型属性时什么被认为是最佳实践,在任何情况下我都不希望它们共享对象的实例(我想要一个深拷贝)。

假设我有一个 class:

public class GeoLocation : SomeBase, ICloneable // Only contains value type properties
{
  public double AValueTypeProperty { get; set; }

  public GeoLocation Clone()
  {
    return new GeoLocation{ AValueTypeProperty = this.AValueTypeProperty };
  }

  object ICloneable.Clone()
  {
    return Clone();
  }
}

此 class 被其他几个 class 用作 属性:

public class PointOfInterest
{
  public GeoLocation Location { get; set; }
  // Other members
}

public class SomeOtherTypeOfPoint
{
  public GeoLocation Location { get; set; }
  // Other members
}

我想避免的是让人们编写一个函数,使这些 classes 共享一个 GeoLocation 实例,而他们只想复制它。由于这些工作将在 class 上独立完成,我们不希望它们相互影响。

如果我想将其中一个的 Location 值(且仅该值)分配给另一个作为 GeoLocation 的新副本,一种方法是克隆。

假设开发人员需要编写这个乱七八糟的函数来将一个点移动到与另一个点相同的位置,但又不能让它们在以后的处理中影响彼此的位置。

public void MovePointOfInterestToSomeOtherTypeOfPoint(PointOfInterest poi, SomeOtherTypeOfPoint other)
{
  poi.Location = other.Location.Clone();
}

以上在我的例子中似乎有点容易出错,因为我们总是想要一个副本,如果有人忘记在这里写“.Clone()”,它可能会导致一些不幸的副作用。

或者在 setter 中克隆 Pop 在两个 classes 中是否正常?如:

public class PointOfInterest
{
  private GeoLocation _loc = null;
  public GeoLocation Location { get => _loc; set => _loc = value.Clone(); }
  // Other members
}

我不是很喜欢,因为看起来我需要一个私有字段才能工作,但至少它看起来比希望开发人员不要忘记克隆更安全。

或者,在 C++ 中,我习惯于在堆栈上创建 classes,并以类似于 C# 中所谓的值类型的方式对待,有什么方法可以在 C# 中实现相同的功能。我希望使用继承,所以结构并不是我想要的。

提前致谢。

我个人的偏好是尽可能使用不可变的 类 来避免这种情况。那么对象是否共享并不重要,因为它无论如何都无法更改。

完全不变性和其他模式有一些变化:

  • 'Popsicle' 不变性 - 对象可以更改到一定程度,然后冻结。
  • ReadOnly 接口 - 对象的所有者可以改变任何它想要的,但只共享一个只读的接口。
  • 将不可变对象包装在可变容器中。需要当前实例的用户可以提取对象,需要最新实例的用户可以共享容器。

这可能不适用于所有类型,在某些情况下可变 类 更适合领域模型。但是,如果您发现需要经常克隆对象,那么应该有一些更好的方法来模拟问题以避免大量克隆。

More reasons why to make objects immutable

从您的实施细节来看,您似乎需要:

  • 管理只有值类型属性的可变数据对象
  • 引用这些对象,每个父对象都有自己的副本

考虑到这一点,您可以利用 Structure types:

Structure types have value semantics. That is, a variable of a structure type contains an instance of the type. By default, variable values are copied on assignment, passing an argument to a method, and returning a method result

这样您就不需要管理对象副本的创建,它将在变量赋值时透明地执行。