【问题标题】:C# String gone from structC# 字符串从结构中消失
【发布时间】:2012-07-06 21:54:44
【问题描述】:

好的.. 我有一个非常尴尬的问题,我认为这与 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 始终返回为 null。我该如何解决这个问题?

编辑:根据要求,我正在添加更多代码以进一步说明问题:

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;
}

【问题讨论】:

  • 如果您可以展示一个简短但完整的程序来演示问题,这将非常有帮助,最好是作为控制台应用程序。哦,看起来你有太多的字段来设计一个精心设计的结构。你有什么理由不把它作为一门课吗?
  • 也提供PointStruct结构。
  • 我怀疑你误解了类和结构之间的区别。与是否需要方法无关。
  • 你说pointValues.Add没有在别处使用; pointValues[key] = ... 是否在任何地方使用过?
  • @SokwhanHuh 是的,但是上面的代码本身不应该失败无论class还是struct。所以:其他事情正在发生。事实仍然是,几乎可以肯定(嗯,不仅仅是“几乎”)不应该是struct。这无助于澄清。

标签: c# .net winforms string dictionary


【解决方案1】:

只要没有巫术(显式字段布局、属性间接等),就绝对没有理由让字段自行擦除,无论它是 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 非常“胖”。还;在大多数情况下,structs 应该是不可变的。

【讨论】:

  • 真正快速而深入的解释。谢谢!
【解决方案2】:

如果存储在Dictionary 中的结构的任何string 字段更改为保存结构存储在Dictionary 中时所持有的值以外的任何值,这将是非常令人惊讶的。你的名字实际上是一个文字"Random String",还是你用那个文字来代表其他一些功能?您是否确认相关功能确实有效?

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

附录

关于可变结构有一件坏事,那就是如果你有任何结构成员,除了构造函数或属性设置器,它会改变this,尝试在只读上下文中使用这样的成员将生成虚假代码,但不会生成任何编译器诊断。正确支持值类型语义的语言和框架要求将变异this 的成员标记为此类,并禁止在只读上下文中使用此类成员,但不幸的是.net 没有此类标记。它只是猜测构造函数和属性设置器会改变底层结构,而 getter 和其他方法不会。如果 `Name 字段是用 struct 方法填写的,例如

无效计算名称(无效) { 名称 = someRandomString(); }

我强烈建议你用静态方法替换它:

无效计算名称(参考结构) { theStruct.Name = someRandomString(); }

如果在PointStruct 的只读实例上调用前一个函数,编译器将——如前所述——编译而不会抱怨,但生成的代码将无法工作。但是,尝试将PointStruct 的只读实例传递给后者会导致编译器错误。

【讨论】:

  • +1,我在想可能是在将结构复制到字典后实际分配了名称。
  • @EricNicholson:这是可能的,但是在将事物存储在 Dictionary 之前让代码分配除名称之外的所有内容,然后再命名似乎很奇怪,即使所讨论的数据类型是可变的班级。不过,你提出了一个有趣的观点(见附录)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-23
  • 2016-01-05
  • 2014-04-28
  • 1970-01-01
  • 2016-09-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多