/// <summary> /// Retrieve all StreamData properties contained within type. /// </summary> /// <param name="type"></param> /// <returns></returns> public static StreamDataInfo[] GetProperties(Type type) { StreamDataInfo[] retVal; // Try fetching from common cache if (cachedProperties.TryGetValue(type, out retVal)) { return(retVal); } BindingFlags bind = BindingFlags.Instance | BindingFlags.Public; if (type.GetAttribute <StreamDataIncludeBaseAttribute>() == null) { bind |= BindingFlags.DeclaredOnly; } retVal = (from pi in type.GetProperties(bind) let attr = (StreamDataAttribute)pi.GetCustomAttributes(typeof(StreamDataAttribute), true).FirstOrDefault() // Only consider SpellData properties where attr != null orderby attr.Order ascending select StreamDataInfo.Create(pi, attr)).ToArray(); cachedProperties.TryAdd(type, retVal); return(retVal); }
public static object[] GetPropertyValues(object obj) { var values = new List <object>(); foreach (var p in StreamDataInfo.GetProperties(obj.GetType())) { values.Add(p.PropertyInfo.SafeGetValue(obj, null)); } return(values.ToArray()); }
/// <summary> /// Retrieve human-readable display of PropertyName=Value /// </summary> /// <param name="obj"></param> /// <returns></returns> public static string[] GetDebugInfo(object obj) { var values = new List <string>(); foreach (var p in StreamDataInfo.GetProperties(obj.GetType())) { // Add each property tagged with SpellDataAttribute in the topmost class if (p.IsArray) { dynamic values2 = p.PropertyInfo.SafeGetValue(obj, null); values.Add(String.Format("{0}={1}", p.PropertyInfo.Name, "{ " + String.Join(", ", values2) + " }")); } else { values.Add(String.Format("{0}={1}", p.PropertyInfo.Name, p.PropertyInfo.SafeGetValue(obj, null))); } } return(values.ToArray()); }
private bool WriteValue(Type dataType, SuperStream stream, object value) { if (dataType == typeof(Byte)) { stream.WriteByte((byte)value); return(true); } if (dataType == typeof(Int64)) { stream.WriteInt64((Int64)value); return(true); } if (dataType == typeof(UInt64)) { stream.WriteUInt64((UInt64)value); return(true); } if (dataType == typeof(Int32)) { stream.WriteInt32((Int32)value); return(true); } if (dataType == typeof(UInt32)) { stream.WriteUInt32((UInt32)value); return(true); } if (dataType == typeof(Int16)) { stream.WriteInt16((Int16)value); return(true); } if (dataType == typeof(UInt16)) { stream.WriteUInt16((UInt16)value); return(true); } if (dataType == typeof(Single)) { stream.WriteSingle((Single)value); return(true); } if (dataType == typeof(Double)) { stream.WriteDouble((Double)value); return(true); } if (dataType == typeof(bool)) { // If bool is true, write 1. Otherwise, write 0. int val = ((bool)value) ? 1 : 0; stream.WriteInt32(val); } if (dataType.IsEnum) { dynamic storeValue = Convert.ChangeType(value, Enum.GetUnderlyingType(dataType)); return(this.WriteValue(storeValue.GetType(), stream, storeValue)); } // Test if type has StreamDataAttribute on properties. // This allows nesting of StreamData-aware task.DataTypes var props = StreamDataInfo.GetProperties(dataType); if (props.Length == 0) { return(false); } StreamData.Serialize(value, stream); // Need to add error condition here. return(true); }
private bool GetValue(Type dataType, SuperStream stream, out object value) { if (dataType == typeof(Byte)) { value = (byte)stream.ReadByte(); return(true); } if (dataType == typeof(Int64)) { value = stream.ReadInt64(); return(true); } if (dataType == typeof(UInt64)) { value = stream.ReadUInt64(); return(true); } if (dataType == typeof(Int32)) { value = stream.ReadInt32(); return(true); } if (dataType == typeof(UInt32)) { value = stream.ReadUInt32(); return(true); } if (dataType == typeof(Int16)) { value = stream.ReadInt16(); return(true); } if (dataType == typeof(UInt16)) { value = stream.ReadUInt16(); return(true); } if (dataType == typeof(Single)) { value = stream.ReadSingle(); return(true); } if (dataType == typeof(Double)) { value = stream.ReadDouble(); return(true); } if (dataType == typeof(bool)) { var val = stream.ReadUInt32(); if (val == 0) { value = false; return(true); } else if (val == 1) { value = true; return(true); } else { throw new Exception("Parsing type bool: Expected value to be either 0 or 1, but it was " + val.ToString()); } } if (dataType.IsEnum) { object readValue; // Read the enums underlying type if (!this.GetValue(Enum.GetUnderlyingType(dataType), stream, out readValue)) { value = null; return(false); } // Parse enum using the read value. value = Enum.ToObject(dataType, readValue); return(true); } // Test if type has StreamDataAttribute on properties. // This allows nesting of StreamData-aware task.DataTypes var props = StreamDataInfo.GetProperties(dataType); if (props.Length == 0) { value = null; return(false); } value = StreamData.Create(dataType, stream); if (value == null) { return(false); } return(true); }
public static StreamDataInfo[] GetProperties(Type type) { return(StreamDataInfo.GetProperties(type)); }
/// <summary> /// Write a given object to stream /// </summary> /// <param name="obj">Object to write</param> /// <param name="ms">Stream to write to</param> public static void Serialize(object obj, SuperStream ms) { if (typeof(IStreamDataFinalizer).IsAssignableFrom(obj.GetType())) { IStreamDataFinalizer fin = (IStreamDataFinalizer)obj; fin.OnSerialize(); } var properties = StreamDataInfo.GetProperties(obj.GetType()); // Parse spell arguments foreach (var pi in properties) { dynamic value = pi.PropertyInfo.SafeGetValue(obj, null); StreamDataParserTask task = new StreamDataParserTask(ms, pi.ReadType, pi.DataType, pi.Attributes); if (pi.IsCollection) { // Find actual length of collection. ulong length; if (pi.IsArray) { length = (ulong)value.Length; } else if (pi.IsList) { length = (ulong)value.Count; } else { throw new Exception("Property is collection, but not array nor list."); } // Write length, and return written length. (Entries= will override length of collection if set) length = pi.WriteContentLength(ms, length); dynamic enumerable = pi.PropertyInfo.SafeGetValue(obj, null); ulong count = 0; foreach (var entry in enumerable) { // Make sure we do not write more entries than we've declared count++; if (count > length) { throw new Exception("Collection contains more items than "); } // Write enry. if (!WriteParserData(task, entry)) { throw new Exception(); } } continue; } else { if (!WriteParserData(task, value)) { throw new Exception(); } } } }
/// <summary> /// Populates an existing object with data from stream. /// </summary> /// <param name="obj"></param> /// <param name="ms"></param> /// <returns></returns> public static object Populate(object obj, SuperStream ms) { var properties = StreamDataInfo.GetProperties(obj.GetType()); bool gracefulStopAtEOF = obj.GetType().GetAttribute <StreamDataGracefulEofAttribute>() != null; dynamic value; // Parse spell arguments foreach (var pi in properties) { if (gracefulStopAtEOF && ms.EOF) { break; } StreamDataParserTask task = new StreamDataParserTask(ms, pi.ReadType, pi.DataType, pi.Attributes); if (pi.IsCollection) { var entries = pi.ReadContentLength(ms); if (pi.IsArray) { var arr = new ArrayList((int)Math.Min(int.MaxValue, entries)); for (ulong i = 0; i < entries; i++) { if (!GetParserData(task, out value)) { throw new Exception(); } arr.Add(value); } var arr2 = arr.ToArray(pi.ReadType); pi.PropertyInfo.SafeSetValue(obj, arr2, null); continue; } else if (pi.IsList) { dynamic list = Activator.CreateInstance( typeof(List <>).MakeGenericType(pi.DataType), (int)Math.Min(int.MaxValue, entries)); for (ulong i = 0; i < entries; i++) { if (!GetParserData(task, out value)) { throw new Exception(); } list.Add(value); } pi.PropertyInfo.SafeSetValue(obj, (object)list, null); } } else { if (!GetParserData(task, out value)) { throw new Exception(); } pi.PropertyInfo.SafeSetValue(obj, (object)value, null); continue; } } if (typeof(IStreamDataFinalizer).IsAssignableFrom(obj.GetType())) { IStreamDataFinalizer fin = (IStreamDataFinalizer)obj; fin.OnDeserialize(); } return(obj); }
public static StreamDataInfo Create(PropertyInfo pi, StreamDataAttribute attr) { var sdi = new StreamDataInfo { PropertyInfo = pi, Entries = attr.Entries, IsArray = false, IsList = false, ReadType = attr.ReadType, Attributes = (from a in pi.GetCustomAttributes(true) where a.GetType() != typeof(StreamDataAttribute) where a is Attribute select a as Attribute).ToArray() }; sdi.IsArray = pi.PropertyType.IsArray; #region Check if it's a IList. if (pi.PropertyType.IsGenericType && pi.PropertyType.GetGenericTypeDefinition() == typeof(List <>)) { sdi.IsList = true; } #endregion #region Validate input and assign proper DataType if (sdi.ReadType != null && sdi.ReadType.IsArray) { throw new ArgumentException(String.Format("{0}->{1}: [StreamDataAttribute] specified ReadType=typeof({2}), but {2} is an array. Specify its member type {3} instead.", pi.DeclaringType.FullName, pi.Name, sdi.ReadType.Name, sdi.ReadType.MemberType)); } if (sdi.IsArray) { sdi.DataType = pi.PropertyType.GetElementType(); } else if (sdi.IsList) { sdi.DataType = pi.PropertyType.GetGenericArguments().First(); } else { sdi.DataType = pi.PropertyType; } if (sdi.ReadType == null) { sdi.ReadType = sdi.DataType; } #endregion #region Verify that collections have correct parameters if (sdi.IsCollection) { if (sdi.Entries != 0 && sdi.Attributes.FirstOrDefault(a => a is StreamDataCollectionLengthAttribute) != null) { throw new ArgumentException(String.Format("{0}->{1}: Cannot specify both [StreamDataCollectionLengthAttribute] and [StreamDataAttribute].Entries>0.", pi.DeclaringType.FullName, pi.Name, sdi.Entries)); } if (sdi.Entries == 0 && sdi.Attributes.FirstOrDefault(a => a is StreamDataCollectionLengthAttribute) == null) { throw new ArgumentException(String.Format("{0}->{1}: Collection must have either [StreamDataCollectionLengthAttribute] or [StreamDataAttribute] specifying Entries>0.", pi.DeclaringType.FullName, pi.Name, sdi.Entries)); } } #endregion return(sdi); }