使用嵌套结构作为属性的类;不起作用

本文关键字:不起作用 属性 嵌套 结构 | 更新日期: 2023-09-27 18:20:36

为什么以下代码不起作用?如果我将h从属性更改为字段,它会起作用!或者,如果我将FileHeaderstruct更改为class,它会起作用!我只是想知道为什么它不起作用。

public class MyFile
{
    public struct FileHeader
    {
        public List<string> ColNames
        {
            get;
            set;
        }
        public void setColNames()
        {
            ColNames = new List<string>();
            ColNames.Add("address");
        }
    }
    public FileHeader h
    {
        get;
        set;
    }
}
public class Program
{
    static void Main(string[] args)
    {
        MyFile o = new MyFile();
        o.h.setColNames();
        Console.WriteLine(o.h.ColNames[0]); // <- Doesn't work! No elements
        string line = System.Console.ReadLine();
    }
}

使用嵌套结构作为属性的类;不起作用

此行:

o.h.setColNames();

相当于:

FileHeader tmp = o.h;
tmp.setColNames();

因为FileHeader是一个结构,所以tmp的值是o中字段值的副本。修改tmp不会更改o.h

我建议:

  • 除非创建自然(小)值类型,否则不会创建自定义结构
  • 所做创建的任何自定义结构都应该是不可变的。在这一点上,更难犯这种错误
  • 遵循.NET命名约定-h的属性和setColNames的方法都违反了
  • 除非有显著的好处,否则应避免嵌套类型。这与你的实际问题无关,但它可能会使各种事情变得更棘手

属性实际上是从您那里抽象出来的方法。它最终成为一个名为Set的方法。。以及一个名为Get。。。它检索一个隐藏的后备变量或设置一个隐藏后备变量。

结构是值类型。当您将值类型传递给方法时,它会复制它们。例如,o.h.setColNames正在添加到副本中,而不是o.h的backing字段的实际实例。

如果你做了一个像这样的房产

public int SomeInteger{get;set;}

它也是一种值类型,但它之所以有效,是因为setter正在设置实际实例,getter会返回一个匹配的副本。

但是在代码中,你用一个类包装了你的结构,所以你总是得到一个没有调用setColNames的副本

这是我在这里发布的一些肮脏的代码,但它演示了如何保持这种设计,并通过让结构引用其父类来设置新副本。

    public class MyFile
{
    public struct FileHeader
    {
        internal MyFile _parent;
        public List<string> ColNames
        {
            get;
            set;
        }
        public void setColNames()
        {
            ColNames = new List<string>();
            ColNames.Add("address");
            _parent._h = this;
        }
    }
    private FileHeader _h = new FileHeader();
    public FileHeader h
    {
        get { return _h; }
    }  
    public MyFile()
    {
        _h._parent = this;
    }
}
class Program
{
    static void Main(string[] args)
    {
        MyFile o = new MyFile();
        o.h.setColNames();
        Console.WriteLine(o.h.ColNames[0]);
        string line = System.Console.ReadLine();
    }
}