具有嵌套结构作为属性的类不起作用

时间:2014-09-03 18:50:35

标签: c# properties struct

为什么以下代码无效? 如果我将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();
    }
}

2 个答案:

答案 0 :(得分:9)

这一行:

o.h.setColNames();

相当于:

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

由于FileHeader是结构,因此tmp的值是o中字段值的副本。修改tmp不会更改o.h

我建议:

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

答案 1 :(得分:1)

属性实际上是从您身上抽象出来的方法。它最终成为一个方法调用Set ..和一个名为Get ...的方法,它检索隐藏的后备变量或设置隐藏的后备变量。

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

如果您制作了像

这样的房产

public int SomeInteger {get;组; }

它也是一个值类型,但它起作用,因为setter正在设置实际的实例,而getter会返回匹配的副本。

但是使用你的代码,你用一个类包装你的struct,所以你总是得到一个没有调用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();
    }
}