C# 使用嵌套结构作为属性初始化';行不通

C# 使用嵌套结构作为属性初始化';行不通,c#,properties,struct,C#,Properties,Struct,为什么下面的代码不起作用? 如果我将h从属性更改为字段,它会工作! 或者,如果我将FileHeader从struct更改为class,它会工作! 我只是在寻找它为什么不起作用的答案 public class MyFile { public struct FileHeader { public List<string> ColNames { get; set; }

为什么下面的代码不起作用? 如果我将
h
从属性更改为字段,它会工作! 或者,如果我将
FileHeader
struct
更改为
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();
    }
}
公共类MyFile
{
公共结构文件头
{
公共列表名称
{
得到;
设置
}
public void setColNames()
{
ColNames=新列表();
ColNames.添加(“地址”);
}
}
公共文件头
{
得到;
设置
}
}
公共课程
{
静态void Main(字符串[]参数)
{
MyFile o=新的MyFile();
o、 h.setColNames();
Console.WriteLine(o.h.ColNames[0]);//此行:

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的备份字段的实际实例

如果你做了一个像

公共整数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();
    }
}
公共类MyFile
{
公共结构文件头
{
内部MyFile\u父级;
公共列表名称
{
得到;
设置
}
public void setColNames()
{
ColNames=新列表();
ColNames.添加(“地址”);
_父项。_h=此项;
}
}
private FileHeader_h=new FileHeader();
公共文件头
{
获取{return}
}  
公共MyFile()
{
_h、 _parent=这个;
}
}
班级计划
{
静态void Main(字符串[]参数)
{
MyFile o=新的MyFile();
o、 h.setColNames();
Console.WriteLine(o.h.ColNames[0]);
string line=System.Console.ReadLine();
}
}

可变结构是邪恶的。现在你知道了其中一个原因“…不起作用”“…起作用了!”-这对我们帮助你没什么帮助。你什么意思不起作用?编译时错误?运行时错误?不正确的结果?我们可以猜测,因为结构有一些特定的特性,可以很容易地找出你在抱怨什么。但说真的…帮我们一点忙。这段代码很可怕,只是一个演示这是一个非常糟糕的设计,因为每次调用setColNames时,它都会将旧结构转储到GC上。+1.另外的建议:注意警告-应该有一个警告出现在导致问题的行上。