1

好的.. 我有一个非常尴尬的问题,我认为这与 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;
}
4

2 回答 2

3

只要没有伏都教(显式字段布局、属性间接等),就绝对没有理由让字段自行擦除,无论它是 aclass还是 a struct

如果它是class,我们也许可以将其归结为其他地方的粗心更新,即

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

这当然会更新与字典引用的相同的基本对象。但这不适用于 a struct,因为副本是分开的(除非直接在数组中更新)。

鉴于您声明pointValues.Add(...)仅在一个地方使用,我能看到导致这种情况的唯一方法是您正在通过索引器在其他地方覆盖它:

pointValues[key] = newValueWithANullName;

尽管如此;除非您有一些非常具体的原因,否则PointStruct成为struct. 在我看来,它应该是一个class. 对于一个struct. 还; 在大多数情况下,structs 应该是不可变的。

于 2012-07-06T12:43:22.530 回答
1

对于存储Dictionary在. 你的名字实际上是一个字面量,还是你用那个字面量来表示其他功能?您是否确认有问题的功能确实有效?stringDictionary"Random String"

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

附录

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

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

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

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

如果在 的只读实例上调用前一个函数PointStruct,则编译器将(如前所述)毫无怨言地编译,但生成的代码将不起作用。但是,尝试将只读实例传递PointStruct给后者会导致编译器错误。

于 2012-07-10T15:29:20.570 回答