2012-07-06 85 views
1

好吧..我有一个非常尴尬的问题,我相信是与C#如何处理值类型与引用类型相关,但我不知道究竟是什么错误。C#字符串去结构

public partial class LogicSimulationViewerForm : Form 
    { 

    private Dictionary<string, PointStruct> pointValues; 


private void SearchPoint(string code) 
    { 
     ReadDefaultPointValuesResponse result = ddcdao.ReadDefaultPoint(points); 
     pointValues = new Dictionary<string, PointStruct>(); 

     for (int j = 0; j < result.pointidentifier.Length; j++) 
     { 
      if (!pointValues.ContainsKey(result.pointidentifier[j])) 
      { 
       PointStruct ps = new PointStruct(); 
       ps.name = "Random String"; 
       ps.pointidentifier = result.pointidentifier[j]; 
       ps.outofservice = result.outofservice[j]; 

       pointValues.Add(result.pointidentifier[j], ps); 
       ... 

pointValues存储为类中的私有字段。现在,在同一类,但不同的功能,如果我尝试做到以下几点:

PointStruct ps = pointValues[s]; 
MessageBox.Show(ps.name); 
MessageBox.Show(ps.pointidentifier); 
MessageBox.Show(ps.outofservice); 

的ps.pointidentifier和ps.outofservice显示正常,但ps.name始终返回空不管我做。我该如何解决这个问题?

编辑:根据要求,我加入更多的代码来进一步说明这个问题:

public struct PointStruct 
{ 
    public string pointidentifier; 
    public string affect; 
    public string outofservice; 
    public string priorityarray; 
    public string pointtype; 
    public string alarmstate; 
    public string correctvalue; 
    public string presentvalue; 
    public string name; 
    public string test; 
} 
+3

如果您可以显示一个显示问题的简短但完整的程序,最好是一个控制台应用程序,这将非常有帮助。噢,看起来你的设计良好的结构中有太多的字段。任何你没有成为课堂的理由? – 2012-07-06 12:31:01

+2

也提供'PointStruct'结构。 – yogi 2012-07-06 12:32:17

+0

@roken我不打电话给pointValues.Add其他地方。 – l46kok 2012-07-06 12:32:22

回答

3

只要没有巫毒(显式的现场布局,物业间接,等等),也绝对没有理由无论是class还是struct,为什么字段应该自行清除。

如果这是一个class,我们也许可以把下来到一个不小心更新别的地方,即

var foo = pointValues[key]; 
// snip 2000 lines 
foo.name = newValue; // which happens to be null 

这当然会更新相同的基本对象,作为一个由字典引用。但不适用struct,因为副本是分开的(除非直接在数组中更新)。我可以看到导致该给予你指出pointValues.Add(...)是只在一个地方使用

的唯一途径,就是要通过索引别处覆盖它:

pointValues[key] = newValueWithANullName; 

所有这一切说,虽然;除非你有一些非常具体的原因,否则PointStruct是一个struct。这在我看来应该是一个classstruct非常“肥”。也;在大多数情况下,struct s应该是不可变的。

+0

真的很快速和深入的解释。谢谢! – l46kok 2012-07-06 12:46:11

+0

+1结构'不变性。 – 2012-07-10 15:54:51

1

这将是存储在Dictionary有任何string领域的变化保持比当结构被存储在Dictionary他们保存的值以外的任何一个结构非常令人吃惊。你的名字实际上是一个文字"Random String",还是你使用该文字来表示一些其他功能?您是否确认所讨论的功能实际上正在工作?

与这里的一些人不同,我非常喜欢可变结构,尽管.net支持它们的限制,因为它们允许结构的所有者控制谁可以改变它。相比之下,如果对可变类对象的引用曾经暴露给外部代码,那么就不知道什么时候可以改变它。 PointStruct是一个结构的事实意味着,您从Dictionary检索的结构的字段内容与结构在存储结构时所具有的字段内容相同的可能性为99.44%。添加支票以确保Name字段在存储到Dictionary时非空,您几乎肯定会发现您的问题。与可变类相比,情况要好得多,你必须检查外部代码以确保没有任何变化。

附录

有关于可变结构一个邪恶的东西,这是,如果你有任何结构成员,不是构造函数或属性setter,它发生变异this等,企图在使用这样的成员只读上下文将生成伪代码,但不会生成任何编译器诊断。正确支持值类型语义的语言和框架要求变异this的成员被标记为这样,并且禁止在只读上下文中使用这些成员,但不幸的是.net没有这样的标记。它只是猜测构造函数和属性设置器会改变底层结构,而getter和其他方法则不会。如果`Name字段用结构方法填充,例如

 
void ComputeName(void) 
{ 
    Name = someRandomString(); 
} 

我强烈建议你用静态方法取代它:

 
void ComputeName(ref theStruct) 
{ 
    theStruct.Name = someRandomString(); 
} 

如果是前者函数调用上的PointStruct只读实例,编译器会 - 为noted-没有投诉的编译,但生成的代码将不起作用。试图将PointStruct的只读实例传递给后者,但会导致编译器错误。

+0

+1,我在想,也许结构被复制到字典后,实际上分配名称。 – 2012-07-10 15:40:03

+0

@EricNicholson:这是可能的,但有代码分配除了名称之前的所有内容,然后将该名字存储在“Dictionary”中,然后执行名称看起来很奇怪,即使所讨论的数据类型是可变类。不过,你提出了一个有趣的观点(见附录)。 – supercat 2012-07-10 15:51:03