C# 中的封装问题

本文关键字:问题 封装 | 更新日期: 2023-09-27 17:56:51

我在C#中的封装遇到了一些问题。 有两种特定情况导致我出现问题,我相信这个问题是相关的。

场景 #1

我有一个看起来像这样的类定义

class MyClass
{
  private int _someField;
  private OtherClass _otherClass;
  public int someField
  {
    get { return _someField; }
    set { _someField = value; }
  }
  public OtherClass otherClass
  {
    get { return _otherClass; }
    set { _otherClass = value; }
  }
}

如果我然后尝试在新代码段中做这样的事情

MyClass theClass = new MyClass();
theClass.otherClass.XYZ += 1;

我被告知无法修改"MyClass.otherClass"的返回值,因为它不是变量。

场景 2#

public partial class trksegType
{
    private wptType[] trkptField;
    private extensionsType extensionsField;
    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute("trkpt")]
    public wptType[] trkpt
    {
        get
        {
            return this.trkptField;
        }
        set
        {
            this.trkptField = value;
        }
    }
}

如果我现在尝试通过 wptType 数组进行 foreach:

foreach (wptType way in trk.trkseg[i])

我被告知 - foreach 语句不能对"trksegType"类型的变量进行操作,因为"trksegType"不包含"GetEnumerator"的公共定义

即使数组应该隐式允许枚举。

谁能解释一下发生了什么以及我可以做些什么来解决这个问题,同时仍然保持最佳实践。

C# 中的封装问题

对于场景 1,我怀疑 OtherClass 已被定义为结构。从属性访问器访问结构时,将创建并返回该结构的新副本(结构是值类型)。更改此新副本上的属性不会影响原始结构。

C# 编译器检测到这一点,并引发这个稍微模糊的错误。

场景 1:

原因很可能是因为您的OtherClass是一个结构而不是一个类。 值语义有点棘手,可变值类型被认为是有害的。因此,您要么想使OtherClass成为类而不是结构体,要么按照这些思路做一些事情:

struct OtherClass
{
    public int XYZ { get; }
    public OtherClass(int xyz)
    {
         XYZ = xyz;
    }
    public OtherClass AddToXYZ(int count)
    {
         return new OtherClass(this.XYZ + count);
    }
}

然后你可以做

myClass.otherClass = myClass.otherClass.AddToXYZ(1);

场景 2:

您要么需要在trksegType上实现IEnumerable以枚举trkpt,要么实际访问枚举的trkpt

通常:

在这两种情况下,您都通过其他对象访问对象,从而违反了封装。看看这里: http://www.csharp-station.com/Tutorials/lesson19.aspx

您还应考虑为对象使用更好(更明确)的名称。 MTTNG VWLS DS NT NCRS rdblty.

(你真的不应该把两个问题放在一个问题上。

场景 1

无法修改 'MyClass.otherClass' 的返回值,因为它不是变量。

发生此错误是因为OtherClass不是一个类,而是一个结构体(也称为值类型)。这意味着访问MyClass.otherClass会复制值,而不是返回引用。您将修改此副本,这将毫无意义。编译器会捕获这一点,因为它始终是一个错误并且永远不会有用。

场景 2

foreach (wptType way in trk.trkseg[i])

您还没有告诉我们trkseg[i]是什么,但如果它是 trksegType 类型,那么答案是:因为trksegType不允许任何枚举。它不实现IEnumerableIEnumerable<T>,也没有自己的GetEnumerator方法。

也许你的意思是写:

foreach (wptType way in trk.trkseg[i].trkpt)

因为trkptwptType数组。(如果您使用更有意义的变量名称而不是没有意义的奇怪字母组合,您可能会更早发现此错误。

我看不出您的第一个示例有什么问题 - 因此请仔细检查错误是否确实存在并纠正错误。

在第二个实例中,看起来您正在尝试迭代 trksegType 的实例,而不是包含的 trkpt 属性。 请尝试foreach (wptType way in trk.trkseg[i].trkpt)