使用Struct内部值的意外行为

时间:2012-08-07 00:15:14

标签: c# struct

*的解决即可。感谢你们的解释,我并没有完全理解在这种情况下使用值类型的含义。

我有一个我从静态类中使用的结构。但是,当我在运行时打印它的内部状态时,行为显示出意外的行为。这是我的结构:

    public struct VersionedObject
    {

        public VersionedObject(object o)
        {
            m_SelectedVer = 0;
            ObjectVersions = new List<object>();
            ObjectVersions.Add(o);
        }

        private int m_SelectedVer;
        public int SelectedVersion
        {
            get
            {
                return m_SelectedVer;
            }

        }

        public List<object> ObjectVersions;//Clarifying:  This is only used to retrieve values,  nothing is .Added from outside this struct in my code.

        public void AddObject(object m)
        {
            ObjectVersions.Add(m);
            m_SelectedVer = ObjectVersions.Count - 1;
        }
    }

测试代码

        VersionedObject vo = new VersionedObject(1);
        vo.AddObject(2);//This is the second call to AddObject()
        //Expected value of vo.SelectedVerion:  1
        //Actual value of vo.SelectedVersion:   1

现在,如果您单独测试此代码,即将其复制到项目中以使其旋转, 将返回预期结果。

问题; 我在生产代码中观察到的是此调试输出:

objectName, ObjectVersions.Count:2, SelectedVer:0,

为什么呢?根据我的理解和测试,在任何情况下都应该完全不可能。

我的随机猜测是存在某种不变性,由于某种原因,通过默认构造函数实例化新结构,并且正在复制ObjectVersions数据,但m_SelectedVersion是私有的,无法复制到新结构?
我使用静态类和方法操作结构是否与它有关?

我很难过,我只是在这一点上发明了疯狂的猜测。

2 个答案:

答案 0 :(得分:1)

Struct是值类型。因此,您最有可能在实际代码中创建对象的多个副本。

考虑简单地将struct更改为class,因为struct的内容不太适合值类型(因为它是可变的并且还包含可变引用类型)。

更多关于“struct is value type”:

首先检查已经有很多好答案的FAQ

值类型按值传递 - 因此,如果调用函数来更新此类对象,则不会更新原始值。您可以将它们视为将整数值传递给函数:即您希望SomeFunction(42)能够更改值42吗?

struct MyStruct { public int V;}
void UpdateStruct(MyStruct x)
{
  x.V = 42; // updates copy of passed in object, changes will not be visible outside.
}
....
var local = new MyStruct{V = 13}
UpdateStruct(local); // Hope to get local.V == 42
if (local.V == 13) {
  // Expected. copy inside UpdateStruct updated,
  // but this "local" is untouched.
}

答案 1 :(得分:1)

为什么这是一个结构而不是一个类?更好的是,为什么要跟踪后备存储的大小(List<T>),而不是让List<T>跟踪您的内容。由于该底层后备存储是公共的,因此可以在没有结构知识的情况下对其进行操作。我怀疑生产代码中的某些内容是在不通过结构的情况下添加到后备存储中的。

如果是我,我会把它设置成这样的东西,虽然我会把它变成一个类......但这几乎肯定是一个突破性的变化:

public struct VersionedObject
{

    public VersionedObject()
    {
        this.ObjectVersions = new List<object>() ;
        return ;
    }

    public VersionedObject(object o) : this()
    {
        ObjectVersions.Add(o);
        return ;
    }
    public VersionedObject( params object[] o ) : this()
    {
        ObjectVersions.AddRange( o ) ;
        return ;
    }

    public int SelectedVersion
    {
        get
        {
            int value = this.ObjectVersions.Count - 1 ;
            return value ;
        }
    }
    public List<object> ObjectVersions  ;

    public void AddObject(object m)
    {
        ObjectVersions.Add(m);
        return ;
    }

}

您会注意到它与您的结构具有相同的语义,但SelectedVersion属性现在反映了后备存储中的实际内容。