3 // Copyright (c) Microsoft Corporation. All rights reserved.
6 /*============================================================
8 ** Class: SerializationInfo
11 ** Purpose: The structure for holding all of the data needed
12 ** for object serialization and deserialization.
15 ===========================================================*/
16 namespace System.Runtime.Serialization
20 using System.Reflection;
21 using System.Runtime.Remoting;
23 using System.Runtime.Remoting.Proxies;
25 using System.Globalization;
26 using System.Diagnostics.Contracts;
27 using System.Security;
29 using System.Runtime.CompilerServices;
32 [System.Runtime.InteropServices.ComVisible(true)]
36 public sealed class SerializationInfo
38 private const int defaultSize = 4;
39 private const string s_mscorlibAssemblySimpleName = "mscorlib";
40 private const string s_mscorlibFileName = s_mscorlibAssemblySimpleName + ".dll";
42 internal String[] m_members;
43 internal Object[] m_data;
44 internal Type[] m_types;
45 internal int m_currMember;
46 internal IFormatterConverter m_converter;
47 private String m_fullTypeName;
48 private String m_assemName;
49 private Type objectType;
50 private bool isFullTypeNameSetExplicit;
51 private bool isAssemblyNameSetExplicit;
52 #if FEATURE_SERIALIZATION
53 private bool requireSameTokenInPartialTrust;
56 public SerializationInfo(Type type, IFormatterConverter converter)
57 #if FEATURE_SERIALIZATION
58 : this(type, converter, false)
63 public SerializationInfo(Type type, IFormatterConverter converter, bool requireSameTokenInPartialTrust)
66 if ((object)type == null)
68 throw new ArgumentNullException("type");
71 if (converter == null)
73 throw new ArgumentNullException("converter");
76 Contract.EndContractBlock();
79 m_fullTypeName = type.FullName;
80 m_assemName = type.Module.Assembly.FullName;
82 m_members = new String[defaultSize];
83 m_data = new Object[defaultSize];
84 m_types = new Type[defaultSize];
86 m_converter = converter;
88 #if FEATURE_SERIALIZATION
89 this.requireSameTokenInPartialTrust = requireSameTokenInPartialTrust;
93 public String FullTypeName
97 return m_fullTypeName;
103 throw new ArgumentNullException("value");
105 Contract.EndContractBlock();
107 m_fullTypeName = value;
108 isFullTypeNameSetExplicit = true;
112 public String AssemblyName
118 #if FEATURE_SERIALIZATION
119 [SecuritySafeCritical]
125 throw new ArgumentNullException("value");
127 Contract.EndContractBlock();
128 #if FEATURE_SERIALIZATION
129 if (this.requireSameTokenInPartialTrust)
131 DemandForUnsafeAssemblyNameAssignments(this.m_assemName, value);
135 isAssemblyNameSetExplicit = true;
138 #if FEATURE_SERIALIZATION
139 [SecuritySafeCritical]
141 public void SetType(Type type)
143 if ((object)type == null)
145 throw new ArgumentNullException("type");
147 Contract.EndContractBlock();
148 #if FEATURE_SERIALIZATION
149 if (this.requireSameTokenInPartialTrust)
151 DemandForUnsafeAssemblyNameAssignments(this.ObjectType.Assembly.FullName, type.Assembly.FullName);
154 if (!Object.ReferenceEquals(objectType, type))
157 m_fullTypeName = type.FullName;
158 m_assemName = type.Module.Assembly.FullName;
159 isFullTypeNameSetExplicit = false;
160 isAssemblyNameSetExplicit = false;
164 private static bool Compare(byte[] a, byte[] b)
166 // if either or both assemblies do not have public key token, we should demand, hence, returning false will force a demand
167 if (a == null || b == null || a.Length == 0 || b.Length == 0 || a.Length != b.Length)
173 for (int i = 0; i < a.Length; i++)
175 if (a[i] != b[i]) return false;
182 [SecuritySafeCritical]
183 internal static void DemandForUnsafeAssemblyNameAssignments(string originalAssemblyName, string newAssemblyName)
185 if (!IsAssemblyNameAssignmentSafe(originalAssemblyName, newAssemblyName))
187 CodeAccessPermission.Demand(PermissionType.SecuritySerialization);
191 internal static bool IsAssemblyNameAssignmentSafe(string originalAssemblyName, string newAssemblyName)
193 if (originalAssemblyName == newAssemblyName)
198 AssemblyName originalAssembly = new AssemblyName(originalAssemblyName);
199 AssemblyName newAssembly = new AssemblyName(newAssemblyName);
201 // mscorlib will get loaded by the runtime regardless of its string casing or its public key token,
202 // so setting the assembly name to mscorlib must always be protected by a demand
203 if (string.Equals(newAssembly.Name, s_mscorlibAssemblySimpleName, StringComparison.OrdinalIgnoreCase) ||
204 string.Equals(newAssembly.Name, s_mscorlibFileName, StringComparison.OrdinalIgnoreCase))
209 return Compare(originalAssembly.GetPublicKeyToken(), newAssembly.GetPublicKeyToken());
212 public int MemberCount
220 public Type ObjectType
228 public bool IsFullTypeNameSetExplicit
232 return isFullTypeNameSetExplicit;
236 public bool IsAssemblyNameSetExplicit
240 return isAssemblyNameSetExplicit;
244 public SerializationInfoEnumerator GetEnumerator()
246 return new SerializationInfoEnumerator(m_members, m_data, m_types, m_currMember);
249 private void ExpandArrays()
252 Contract.Assert(m_members.Length == m_currMember, "[SerializationInfo.ExpandArrays]m_members.Length == m_currMember");
254 newSize = (m_currMember * 2);
257 // In the pathological case, we may wrap
259 if (newSize < m_currMember)
261 if (Int32.MaxValue > m_currMember)
263 newSize = Int32.MaxValue;
268 // Allocate more space and copy the data
270 String[] newMembers = new String[newSize];
271 Object[] newData = new Object[newSize];
272 Type[] newTypes = new Type[newSize];
274 Array.Copy(m_members, newMembers, m_currMember);
275 Array.Copy(m_data, newData, m_currMember);
276 Array.Copy(m_types, newTypes, m_currMember);
279 // Assign the new arrys back to the member vars.
281 m_members = newMembers;
286 public void AddValue(String name, Object value, Type type)
290 throw new ArgumentNullException("name");
293 if ((object)type == null)
295 throw new ArgumentNullException("type");
297 Contract.EndContractBlock();
300 // Walk until we find a member by the same name or until
301 // we reach the end. If we find a member by the same name,
303 for (int i = 0; i < m_currMember; i++)
305 if (m_members[i].Equals(name))
307 BCLDebug.Trace("SER", "[SerializationInfo.AddValue]Tried to add ", name, " twice to the SI.");
309 throw new SerializationException(Environment.GetResourceString("Serialization_SameNameTwice"));
313 AddValue(name, value, type, m_currMember);
317 public void AddValue(String name, Object value)
321 AddValue(name, value, typeof(Object));
325 AddValue(name, value, value.GetType());
329 public void AddValue(String name, bool value)
331 AddValue(name, (Object)value, typeof(bool));
334 public void AddValue(String name, char value)
336 AddValue(name, (Object)value, typeof(char));
340 [CLSCompliant(false)]
341 public void AddValue(String name, sbyte value)
343 AddValue(name, (Object)value, typeof(sbyte));
346 public void AddValue(String name, byte value)
348 AddValue(name, (Object)value, typeof(byte));
351 public void AddValue(String name, short value)
353 AddValue(name, (Object)value, typeof(short));
356 [CLSCompliant(false)]
357 public void AddValue(String name, ushort value)
359 AddValue(name, (Object)value, typeof(ushort));
362 public void AddValue(String name, int value)
364 AddValue(name, (Object)value, typeof(int));
367 [CLSCompliant(false)]
368 public void AddValue(String name, uint value)
370 AddValue(name, (Object)value, typeof(uint));
373 public void AddValue(String name, long value)
375 AddValue(name, (Object)value, typeof(long));
378 [CLSCompliant(false)]
379 public void AddValue(String name, ulong value)
381 AddValue(name, (Object)value, typeof(ulong));
384 public void AddValue(String name, float value)
386 AddValue(name, (Object)value, typeof(float));
389 public void AddValue(String name, double value)
391 AddValue(name, (Object)value, typeof(double));
394 public void AddValue(String name, decimal value)
396 AddValue(name, (Object)value, typeof(decimal));
399 public void AddValue(String name, DateTime value)
401 AddValue(name, (Object)value, typeof(DateTime));
404 internal void AddValue(String name, Object value, Type type, int index)
407 // If we need to expand the arrays, do so.
409 if (index >= m_members.Length)
415 // Add the data and then advance the counter.
417 m_members[index] = name;
418 m_data[index] = value;
419 m_types[index] = type;
423 /*=================================UpdateValue==================================
424 **Action: Finds the value if it exists in the current data. If it does, we replace
425 ** the values, if not, we append it to the end. This is useful to the
426 ** ObjectManager when it's performing fixups, but shouldn't be used by
427 ** clients. Exposing out this functionality would allow children to overwrite
428 ** their parent's values.
430 **Arguments: name -- the name of the data to be updated.
431 ** value -- the new value.
432 ** type -- the type of the data being added.
433 **Exceptions: None. All error checking is done with asserts.
434 ==============================================================================*/
435 internal void UpdateValue(String name, Object value, Type type)
437 Contract.Assert(null != name, "[SerializationInfo.UpdateValue]name!=null");
438 Contract.Assert(null != value, "[SerializationInfo.UpdateValue]value!=null");
439 Contract.Assert(null != (object)type, "[SerializationInfo.UpdateValue]type!=null");
441 int index = FindElement(name);
444 AddValue(name, value, type, m_currMember);
448 m_members[index] = name;
449 m_data[index] = value;
450 m_types[index] = type;
455 private int FindElement(String name)
459 throw new ArgumentNullException("name");
461 Contract.EndContractBlock();
462 BCLDebug.Trace("SER", "[SerializationInfo.FindElement]Looking for ", name, " CurrMember is: ", m_currMember);
463 for (int i = 0; i < m_currMember; i++)
465 Contract.Assert(m_members[i] != null, "[SerializationInfo.FindElement]Null Member in String array.");
466 if (m_members[i].Equals(name))
474 /*==================================GetElement==================================
475 **Action: Use FindElement to get the location of a particular member and then return
476 ** the value of the element at that location. The type of the member is
477 ** returned in the foundType field.
478 **Returns: The value of the element at the position associated with name.
479 **Arguments: name -- the name of the element to find.
480 ** foundType -- the type of the element associated with the given name.
481 **Exceptions: None. FindElement does null checking and throws for elements not
483 ==============================================================================*/
484 private Object GetElement(String name, out Type foundType)
486 int index = FindElement(name);
489 throw new SerializationException(Environment.GetResourceString("Serialization_NotFound", name));
492 Contract.Assert(index < m_data.Length, "[SerializationInfo.GetElement]index<m_data.Length");
493 Contract.Assert(index < m_types.Length, "[SerializationInfo.GetElement]index<m_types.Length");
495 foundType = m_types[index];
496 Contract.Assert((object)foundType != null, "[SerializationInfo.GetElement]foundType!=null");
497 return m_data[index];
500 [System.Runtime.InteropServices.ComVisible(true)]
502 private Object GetElementNoThrow(String name, out Type foundType)
504 int index = FindElement(name);
511 Contract.Assert(index < m_data.Length, "[SerializationInfo.GetElement]index<m_data.Length");
512 Contract.Assert(index < m_types.Length, "[SerializationInfo.GetElement]index<m_types.Length");
514 foundType = m_types[index];
515 Contract.Assert((object)foundType != null, "[SerializationInfo.GetElement]foundType!=null");
516 return m_data[index];
520 // The user should call one of these getters to get the data back in the
524 [System.Security.SecuritySafeCritical] // auto-generated
525 public Object GetValue(String name, Type type)
528 if ((object)type == null)
530 throw new ArgumentNullException("type");
532 Contract.EndContractBlock();
534 RuntimeType rt = type as RuntimeType;
536 throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeType"));
541 value = GetElement(name, out foundType);
543 if (RemotingServices.IsTransparentProxy(value))
545 RealProxy proxy = RemotingServices.GetRealProxy(value);
546 if (RemotingServices.ProxyCheckCast(proxy, rt))
551 if (Object.ReferenceEquals(foundType, type) || type.IsAssignableFrom(foundType) || value == null)
556 Contract.Assert(m_converter != null, "[SerializationInfo.GetValue]m_converter!=null");
558 return m_converter.Convert(value, type);
561 [System.Security.SecuritySafeCritical] // auto-generated
562 [System.Runtime.InteropServices.ComVisible(true)]
564 internal Object GetValueNoThrow(String name, Type type)
569 Contract.Assert((object)type != null, "[SerializationInfo.GetValue]type ==null");
570 Contract.Assert(type is RuntimeType, "[SerializationInfo.GetValue]type is not a runtime type");
572 value = GetElementNoThrow(name, out foundType);
576 if (RemotingServices.IsTransparentProxy(value))
578 RealProxy proxy = RemotingServices.GetRealProxy(value);
579 if (RemotingServices.ProxyCheckCast(proxy, (RuntimeType)type))
584 if (Object.ReferenceEquals(foundType, type) || type.IsAssignableFrom(foundType) || value == null)
589 Contract.Assert(m_converter != null, "[SerializationInfo.GetValue]m_converter!=null");
591 return m_converter.Convert(value, type);
594 public bool GetBoolean(String name)
599 value = GetElement(name, out foundType);
600 if (Object.ReferenceEquals(foundType, typeof(bool)))
604 return m_converter.ToBoolean(value);
607 public char GetChar(String name)
612 value = GetElement(name, out foundType);
613 if (Object.ReferenceEquals(foundType, typeof(char)))
617 return m_converter.ToChar(value);
620 [CLSCompliant(false)]
621 public sbyte GetSByte(String name)
626 value = GetElement(name, out foundType);
627 if (Object.ReferenceEquals(foundType, typeof(sbyte)))
631 return m_converter.ToSByte(value);
634 public byte GetByte(String name)
639 value = GetElement(name, out foundType);
640 if (Object.ReferenceEquals(foundType, typeof(byte)))
644 return m_converter.ToByte(value);
647 public short GetInt16(String name)
652 value = GetElement(name, out foundType);
653 if (Object.ReferenceEquals(foundType, typeof(short)))
657 return m_converter.ToInt16(value);
660 [CLSCompliant(false)]
661 public ushort GetUInt16(String name)
666 value = GetElement(name, out foundType);
667 if (Object.ReferenceEquals(foundType, typeof(ushort)))
669 return (ushort)value;
671 return m_converter.ToUInt16(value);
674 public int GetInt32(String name)
679 value = GetElement(name, out foundType);
680 if (Object.ReferenceEquals(foundType, typeof(int)))
684 return m_converter.ToInt32(value);
687 [CLSCompliant(false)]
688 public uint GetUInt32(String name)
693 value = GetElement(name, out foundType);
694 if (Object.ReferenceEquals(foundType, typeof(uint)))
698 return m_converter.ToUInt32(value);
701 public long GetInt64(String name)
706 value = GetElement(name, out foundType);
707 if (Object.ReferenceEquals(foundType, typeof(long)))
711 return m_converter.ToInt64(value);
714 [CLSCompliant(false)]
715 public ulong GetUInt64(String name)
720 value = GetElement(name, out foundType);
721 if (Object.ReferenceEquals(foundType, typeof(ulong)))
725 return m_converter.ToUInt64(value);
728 public float GetSingle(String name)
733 value = GetElement(name, out foundType);
734 if (Object.ReferenceEquals(foundType, typeof(float)))
738 return m_converter.ToSingle(value);
742 public double GetDouble(String name)
747 value = GetElement(name, out foundType);
748 if (Object.ReferenceEquals(foundType, typeof(double)))
750 return (double)value;
752 return m_converter.ToDouble(value);
755 public decimal GetDecimal(String name)
760 value = GetElement(name, out foundType);
761 if (Object.ReferenceEquals(foundType, typeof(decimal)))
763 return (decimal)value;
765 return m_converter.ToDecimal(value);
768 public DateTime GetDateTime(String name)
773 value = GetElement(name, out foundType);
774 if (Object.ReferenceEquals(foundType, typeof(DateTime)))
776 return (DateTime)value;
778 return m_converter.ToDateTime(value);
781 public String GetString(String name)
786 value = GetElement(name, out foundType);
787 if (Object.ReferenceEquals(foundType, typeof(String)) || value == null)
789 return (String)value;
791 return m_converter.ToString(value);
794 internal string[] MemberNames
803 internal object[] MemberValues