奇怪的(对我来说)关于DataContractSerializer构造的类实例的行为没有从函数“返回”

时间:2014-01-24 22:29:21

标签: c# datacontractserializer

抱歉 - 这应该是根据' ref'提交的。参数。我正在关注这个问题并没有真正思考。答案是ModifiedSerialized函数应该使用ref参数来修改' target'直接

ModifySerialized(ref DataClass target){...}

鉴于此runtime.serializable类:

[DataContract]
public class DataClass
{
        [DataMember(Order = 0)]
        public int Number
        {
            get;
            set;
        }

        [DataMember(Order = 1)]
        public string Name
        {
            get;
            set;
        }

        override public string ToString()
        {
            return "DataClass: " + Name + " --  " + Number;
        }
}

和一些锻炼课程:

class Test
{
    public Test()
    {
        DataClass testDataClass = new DataClass() { Name = "Foo", Number = 123 };
        ModifySerialized(testDataClass);
        Console.WriteLine(testDataClass);
    }

    private void ModifySerialized(DataClass target)
    {
        MemoryStream stream = new MemoryStream();
        DataContractSerializer serializer = new DataContractSerializer(typeof(DataClass));
        serializer.WriteObject(stream, new DataClass() { Name = "serialized", Number = 777 });
        stream.Seek(0, SeekOrigin.Begin);
        string sDebug = ASCIIEncoding.ASCII.GetString(stream.GetBuffer());
        Console.WriteLine(sDebug);
        target = (DataClass)serializer.ReadObject(stream);
        Console.WriteLine(target);
    }
}

我希望在调用ModifySerialized(target)之后,在Test ctr中输出到控制台是这样的:

DataClass: name = serialized -- number = 777

但是,调用ModifySerialized(target)后的输出仍会显示

DataClass: name Foo number 123 (or similar)

- > (DataClass)目标未被修改

但是,在对ModifySerialized的函数调用中,控制台输出是我对“目标”所期望的。 (即序列化,777)。

我错过了什么?函数的参数是参考,不是吗?应该修改引用的值,不是吗?相反,如果在ModifySerialized(target)内{我只设置Number=1234,则在按照预期从Test调用后,该值将正确输出到控制台。

谢谢......

3 个答案:

答案 0 :(得分:3)

ModifySerialized方法中,您将target参数设置为DataClass的新实例;但是,由于参数未通过引用传递,testDataClass方法中的Test变量仍然引用从未修改过的原始实例。通过引用传递参数将产生您期望的行为。

  

我错过了什么?函数的参数是参考,不是吗?应该修改引用的值,不是吗?相反,如果在ModifySerialized(target)中,我只设置Number = 1234,那么在按照预期从Test调用后,该值将正确输出到控制台。

我认为你在这里混淆了两个概念:

  • 值类型与参考类型
  • 按值与参考值传递参数

这里,参数的类型是引用类型,这意味着参数的值是引用;但是引用是按值传递的,因此为参数指定新实例不会更改原始引用。

有关更详细的解释,我建议您阅读Jon Skeet的优秀文章:Parameter passing in C#

答案 1 :(得分:0)

您希望原始变量testDataClass的值会更改,但它不会像这样工作。它的值的副本实际上传递给方法,并且在执行期间被查询,但它不能反映到原始变量。为此,您应该返回新值作为方法结果:

private DataClass ModifySerialized(DataClass target)
{
    MemoryStream stream = new MemoryStream();
    DataContractSerializer serializer = new DataContractSerializer(typeof(DataClass));
    serializer.WriteObject(stream, new DataClass() { Name = "serialized", Number = 777 });
    stream.Seek(0, SeekOrigin.Begin);
    string sDebug = ASCIIEncoding.ASCII.GetString(stream.GetBuffer());
    Console.WriteLine(sDebug);
    target = (DataClass)serializer.ReadObject(stream);
    Console.WriteLine(target);
    return target; // here
}

public Test()
{
    DataClass testDataClass = new DataClass() { Name = "Foo", Number = 123 };
    testDataClass = ModifySerialized(testDataClass);
    Console.WriteLine(testDataClass);
}

或使用ref

private DataClass ModifySerialized(ref DataClass target)
{
    MemoryStream stream = new MemoryStream();
    DataContractSerializer serializer = new DataContractSerializer(typeof(DataClass));
    serializer.WriteObject(stream, new DataClass() { Name = "serialized", Number = 777 });
    stream.Seek(0, SeekOrigin.Begin);
    string sDebug = ASCIIEncoding.ASCII.GetString(stream.GetBuffer());
    Console.WriteLine(sDebug);
    target = (DataClass)serializer.ReadObject(stream);
    Console.WriteLine(target);
}

public Test()
{
    DataClass testDataClass = new DataClass() { Name = "Foo", Number = 123 };
    ModifySerialized(ref testDataClass);
    Console.WriteLine(testDataClass);
}

答案 2 :(得分:0)

请记住,serializer.ReadObject会返回刚从流中读取的新对象。它将替换函数中target变量记住的对象,但此操作不会更改外部变量记住的内容。

为此,请尝试ModifySerialized(ref DataClass target)。但仍然要记住它不会“改变对象内容”。它将忘记旧实例并将其替换为新实例。

您可以在调试器中通过“Make Object ID”检查它,看看哪个变量引用对象#1,哪个变量引用#2等