Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien

[C#] Object Clone, Serialization*

Pagina: 1
Acties:
  • 110 views sinds 30-01-2008
  • Reageer

  • 0nline
  • Registratie: September 2006
  • Laatst online: 29-04-2018
Ik zit te suf te zoeken en dingen uit te proberen, maar kom er niet uit. Misschien dat jullie het zien...
Ik heb een class, welke ICloneable implementeert en meerdere (sub) classes heeft:

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
[Serializable()]
public class ClassA: ICloneable, IDisposable
{
   [field:NonSerializable]
   public event SomeEventHandler MyEventHandler;
   private Int32 _SomeId;

   [Serializable()]
   public class ClassB: EenAnderClass (<-- ook gemarkeerd als serializable)
   {
      private Int32 _InternalId; 
      private Decimal _Value;
      ...
   }

   [Serializable()]
   public class ClassC
   {
      private Int32 _InternalId;
      private String _Value;
      ...
   }

   public object Clone()
   {
      ...
   }
}


Ergens in mn programma doe ik het volgende:

C#:
1
2
3
4
5
6
7
8
9
10
11
(myClass is ergens anders al geinstantieerd/gecreeerd etc)

private void Button_Click(Object sender, EventArgs e)
{
   ClassA tmpClass = (MyClass)myClass.Clone();

   if (FunctieAanRoep(tmpClass))
   {
      myClass = (MyClass)tmpClass.Clone();
   }
}


Wanneer de functie terug keert (en true geeft), krijg ik de volgende fout:

code:
1
2
3
Het type System.ComponentModel.ReflectPropertyDescriptor in assembly System, 
Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 is 
niet als serialiseerbaar gemarkeerd.


Wat ik probeer is:
wanneer de gebruiker het object (tmpClass) heeft gewijzigd en ok heeft geklikt,
de waardes van tmpClass in myClass te zetten.
(Een aantal controls op het form zijn weer gebound aan tmpClass)

Iemand een idee wat ik hier fout doe?

Wetten zijn gemaakt om gebroken te worden


  • whoami
  • Registratie: December 2000
  • Laatst online: 21:14
Hoe ziet je Clone method er uit ? Ik begrijp dat je je object serializeert en deserialiseert.
Ik begrijp ook dat je die fout pas krijgt als je de Clone method aanroept van het geclonede object ?

https://fgheysels.github.io/


  • 0nline
  • Registratie: September 2006
  • Laatst online: 29-04-2018
whoami schreef op dinsdag 11 september 2007 @ 16:12:
Hoe ziet je Clone method er uit ? Ik begrijp dat je je object serializeert en deserialiseert.
Ik begrijp ook dat je die fout pas krijgt als je de Clone method aanroept van het geclonede object ?
het clone gedeelte ziet er als volgt uit:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
        public object Clone()
        {
            MyClass _clonedObject = null;
            BinaryFormatter _formatter = null;
            MemoryStream _memStream = null;

            try
            {
                _formatter = new BinaryFormatter();
                _memStream = new MemoryStream();

                _formatter.Serialize(_memStream, this);
                _memStream.Seek(0, System.IO.SeekOrigin.Begin);

                _clonedObject = (MyClass)_formatter.Deserialize(_memStream);

                return _clonedObject;
            }
            finally
            {
                if (_memStream != null)
                    _memStream.Close();

                _memStream = null;
            }
        }


Ja, inderdaad, op het moment dat de 2e clone aangeroepen wordt, krijg ik de fout.

(Ben nu de MemberwiseClone aan het uitproberen)

[ Voor 3% gewijzigd door 0nline op 11-09-2007 16:21 ]

Wetten zijn gemaakt om gebroken te worden


  • whoami
  • Registratie: December 2000
  • Laatst online: 21:14
waarschijnlijk ben je deze ook al tegengekomen:
klik

Blijkbaar een bug in .NET mbt het serializeren van events / delegates ?

https://fgheysels.github.io/


  • Niemand_Anders
  • Registratie: Juli 2006
  • Laatst online: 09-07-2024

Niemand_Anders

Dat was ik niet..

Je zult de ISerializable interface moeten gaan implementeren. Het Serializable attribute serializeert alleen public property values. Interne variabelen, zoals _SomeId, worden niet meegenomen (deze zijn niet via reflection opvraagbaar).

Door ISerialize te implementeren geef je zelf aan welke variabelen moeten worden 'onthouden'. De MSDN Documentatie bevat voorbeeld code hoe je ISerialize implementeerd.

If it isn't broken, fix it until it is..


  • Niemand_Anders
  • Registratie: Juli 2006
  • Laatst online: 09-07-2024

Niemand_Anders

Dat was ik niet..

whoami schreef op dinsdag 11 september 2007 @ 16:25:
Blijkbaar een bug in .NET mbt het serializeren van events / delegates ?
Het event heeft het attribute NonSerializable en wordt dus niet meegenomen in het serializatie process.

If it isn't broken, fix it until it is..


  • 0nline
  • Registratie: September 2006
  • Laatst online: 29-04-2018
Ja die pagina heb ik idd al gelezen, maar kan er niet uit opmaken dat het een bug is.
[field:NonSerializable], daar krijg ik geen warning op (gebruik ook 2.0)

Heb als test het event verwijderd, maar zonder success :(

Ik denk dat ik voorlopig de MemberwiseClone ga gebruiken, totdat ik een oplossing heb gevonden.
Als iemand een suggiestie heeft, ik sta voor (bijna) alles open :-)

Whoami, iig bedankt voor je snelle reply

(Mocht ik meer "ontdekt" hebben mbt de "bug" van ms, dan zal ik het hier posten voor de geinteresserden)

edit:

zal het uitproberen niemand_anders, zag je bericht te laat :D

[ Voor 7% gewijzigd door 0nline op 11-09-2007 16:51 ]

Wetten zijn gemaakt om gebroken te worden


  • whoami
  • Registratie: December 2000
  • Laatst online: 21:14
Niemand_Anders schreef op dinsdag 11 september 2007 @ 16:40:
Je zult de ISerializable interface moeten gaan implementeren. Het Serializable attribute serializeert alleen public property values. Interne variabelen, zoals _SomeId, worden niet meegenomen (deze zijn niet via reflection opvraagbaar).
Da's niet waar.
Als je een class het Serializable attribute geeft, kan alles van die class gewoon geserialized worden.
De Soap & BinaryFormatter serializeren gewoon alles, ook als de fields private zijn.
ISerializable moet je enkel implementeren als je echt aangepaste functionaliteit wil.
Je kan hier natuurlijk wel proberen om ISerialize te implementeren, en te gaan aangeven dat alles moet geserialized worden, behalve die event natuurlijk.

De XmlSerializer echter, die serialized idd enkel de public properties / fields.
Het event heeft het attribute NonSerializable en wordt dus niet meegenomen in het serializatie process
Idd, maar, als je die andere pagina bekijkt waar ik naar link, dan zie je dat die persoon een warning krijgt op dat [nonserialize] attribute:
warning CS0657: 'field' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'method, event'. All attributes in this block will be ignored.
Waarschijnlijk wordt die dus gewoon genegeerd; al zegt de TS hier dat hij die warning niet krijgt ....

[ Voor 39% gewijzigd door whoami op 11-09-2007 17:10 ]

https://fgheysels.github.io/


  • 0nline
  • Registratie: September 2006
  • Laatst online: 29-04-2018
whoami schreef op dinsdag 11 september 2007 @ 17:07:

[...]
Idd, maar, als je die andere pagina bekijkt waar ik naar link, dan zie je dat die persoon een warning krijgt op dat [nonserialize] attribute:
[...]
Waarschijnlijk wordt die dus gewoon genegeerd; al zegt de TS hier dat hij die warning niet krijgt ....
Misschien dat ie een sp mist o.i.d.
als ik het woordje 'field:' ervoor weghaal, krijg ik een error.

Ik heb ff snel een test progje gemaakt, waar ik ong. hetzelfde doe.
Alleen ditmaal met veel simpelere classes (slechts 2 private velden/properties, events etc).
Hierin kan ik zoveel clonen als ik wil, maar geen exception... :?
(zal zo de code posten).

Vreemde is: Waarom werkt de 1e clone method wel en de 2e niet (in mijn 'echte' programma)...
C#:
1
2
3
//_objectA is ergens anders gecreeerd/gezet)
ClassA _tmpObj = this._objectA.Clone(); //<-- Gaat goed
this._objectA = _tmpObj.Clone() //<-- exception


trouwens, als ik het object dat gecloned is bekijk, zie ik wel de private fields e.d.
Alleen de events zijn null, wat ook logisch is, omdat ie gemarkeerd is als NonSerialized.
(Markeer je de events niet als 'NonSerialized', dan krijg je een exception).

Ik ga ff al mijn classes onder de loep nemen, vind dit erg vreemd.

Wetten zijn gemaakt om gebroken te worden


  • 0nline
  • Registratie: September 2006
  • Laatst online: 29-04-2018
Onderstaand in je 'public partial class Form1: form' plakken

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
        private System.Windows.Forms.TextBox textBox1;
        private System.Windows.Forms.Button button1;

        private MyClass classA = new MyClass();

        public Form1()
        {
            this.textBox1 = new System.Windows.Forms.TextBox();
            this.button1 = new System.Windows.Forms.Button();
            this.SuspendLayout();
            // 
            // textBox1
            // 
            this.textBox1.Location = new System.Drawing.Point(12, 12);
            this.textBox1.Multiline = true;
            this.textBox1.Name = "textBox1";
            this.textBox1.Size = new System.Drawing.Size(443, 187);
            this.textBox1.TabIndex = 3;
            // 
            // button1
            // 
            this.button1.Location = new System.Drawing.Point(12, 205);
            this.button1.Name = "button1";
            this.button1.Size = new System.Drawing.Size(75, 23);
            this.button1.TabIndex = 4;
            this.button1.Text = "button1";
            this.button1.UseVisualStyleBackColor = true;
            this.button1.Click += new System.EventHandler(this.button1_Click);
            // 
            // Form1
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(470, 239);
            this.Controls.Add(this.button1);
            this.Controls.Add(this.textBox1);
            this.Name = "Form1";
            this.Text = "Form1";
            this.Load += new System.EventHandler(this.Form1_Load);
            this.ResumeLayout(false);
            this.PerformLayout();
            InitializeComponent();
        }

        [Serializable()]
        public class MyClass : ICloneable, IDisposable
        {
            [field:NonSerialized]
            public event SomeEventHandler MyEventHandler;

            private Int32 _SomeId;
            private String _SomeString;

            #region ICloneable Members

            public object Clone()
            {
                MyClass _clonedObject = null;
                System.Runtime.Serialization.Formatters.Binary.BinaryFormatter _formatter = null;
                System.IO.MemoryStream _memStream = null;

                try
                {
                    _formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
                    _memStream = new System.IO.MemoryStream();

                    _formatter.Serialize(_memStream, this);
                    _memStream.Seek(0, System.IO.SeekOrigin.Begin);

                    _clonedObject = (MyClass)_formatter.Deserialize(_memStream);

                    return _clonedObject;
                }
                finally
                {
                    if (_memStream != null)
                        _memStream.Close();

                    _memStream = null;
                }
            }

            #endregion

            #region IDisposable Members

            public void Dispose()
            {
                this.Dispose(true);
                GC.SuppressFinalize(this);
            }

            protected virtual void Dispose(Boolean disposing)
            {
                if (disposing)
                {

                }
            }

            ~MyClass()
            {
                this.Dispose(false);
            }
            #endregion

            public Int32 SomeId
            {
                get
                {
                    return this._SomeId;
                }
                set
                {
                    this._SomeId = value;
                }
            }

            public String SomeString
            {
                get
                {
                    return this._SomeString;
                }
                set
                {
                    this._SomeString = value;
                }
            }

            public override string ToString()
            {
                if (this.MyEventHandler != null)
                    this.MyEventHandler(null, new SomeEventArgs());

                return this._SomeString;
                //return base.ToString();
            }

        }

        [Serializable()]
        public class MyClassB : MyClass
        {
            private Int32 _Value;

            public Int32 Value
            {
                get
                {
                    return this._Value;
                }
                set
                {
                    this._Value = value;
                }
            }
        }

        public class SomeEventArgs : EventArgs
        {
            private String _SomeString;

            public SomeEventArgs()
                : base()
            {
                this._SomeString = "blaat";
            }

            public String SomeString
            {
                get
                {
                    return this._SomeString;
                }
            }
        }

        public delegate void SomeEventHandler(Object sender, SomeEventArgs e);

        public Boolean blaat(MyClass classD)
        {
            //Simulate a user editing this object
            classD.SomeId = 5;
            classD.SomeString = "Class D";
            return true;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            this.classA.MyEventHandler -= new SomeEventHandler(this.classA_MyEventHandler);
            this.classA.MyEventHandler += new SomeEventHandler(this.classA_MyEventHandler);
        }

        private void classA_MyEventHandler(object sender, Form1.SomeEventArgs e)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        private void button1_Click(object sender, EventArgs e)
        {
            MyClass classD = null;
            this.classA.SomeId = 1;
            this.classA.SomeString = "Class A";

            textBox1.Text += String.Format("{0}  {1}{2}", classA.SomeId, classA.SomeString, Environment.NewLine);

            classD = (MyClass)this.classA.Clone();
            textBox1.Text += String.Format("Class D Before {0}  {1}{2}", classD.SomeId, classD.SomeString, Environment.NewLine);
            if (this.blaat(classD))
            {
                classA = (MyClass)classD.Clone();
            }
            textBox1.Text += String.Format("Class D After {0}  {1}{2}", classD.SomeId, classD.SomeString, Environment.NewLine);
            textBox1.Text += String.Format("Class A After edit/clone {0}  {1}{2}", this.classA.SomeId, this.classA.SomeString, Environment.NewLine);
        }

Wetten zijn gemaakt om gebroken te worden


  • farlane
  • Registratie: Maart 2000
  • Laatst online: 30-11 00:17
Kan het misschien een variabele in je class zijn die de boel verziekt? Ik weet dat ik een class afgeleid had van een dictionary waarbij ik specifiek een constructor moest toevoegen:

C#:
1
2
3
4
5
    [Serializable( )]
    public class Blaat : Dictionary
    {
        protected Blaat ( SerializationInfo info, StreamingContext context ) : base( info, context ){}
    }

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


  • whoami
  • Registratie: December 2000
  • Laatst online: 21:14
Mja, maar in dat geval zou je een andere exception krijgen (iets van 'could not deserialize bla, missing constructor' oid)

https://fgheysels.github.io/


  • 0nline
  • Registratie: September 2006
  • Laatst online: 29-04-2018
farlane schreef op woensdag 12 september 2007 @ 11:51:
Kan het misschien een variabele in je class zijn die de boel verziekt? Ik weet dat ik een class afgeleid had van een dictionary waarbij ik specifiek een constructor moest toevoegen:

C#:
1
2
3
4
5
    [Serializable( )]
    public class Blaat : Dictionary
    {
        protected Blaat ( SerializationInfo info, StreamingContext context ) : base( info, context ){}
    }
Dan zou ie bij de 1e clone toch al fout moeten gaan, lijkt mij.

Wetten zijn gemaakt om gebroken te worden

Pagina: 1