/// <summary>Creates a single TargetType object given a record string.</summary> /// <param name="text">Record string to deserialize.</param> /// <returns>Newly created TargetType object.</returns> /// <exception cref="ArgumentNullException">Thrown if text is null.</exception> /// <exception cref="TextSerializationException">Thrown if the number of fields in the record doesn't match that in TargetType.</exception> public TTargetType Deserialize(string text) { if (text == null) { throw new ArgumentNullException("text", "text cannot be null"); } // Create the correct return objects depending on whether this is a value or reference type // This makes a difference for reflection later on when populating the fields dynamically. TTargetType returnObj = new TTargetType(); ValueType returnStruct = null; if (_type.IsValueType) { object tempObj = returnObj; returnStruct = (ValueType)tempObj; } // Parse the record into it's individual fields depending on the type of serializer this is List <string> parseList = Parse(text); int requiredCount = _textFields.Values.Count(attr => !attr.Optional); if (parseList.Count < requiredCount || parseList.Count > _textFields.Count) { throw new TextSerializationException("TargetType field count doesn't match number of items in text"); } // For each field that is parsed in the string, populate the correct corresponding field in the TargetType TextFieldAttribute[] attributes = _textFields.Values.ToArray(); for (int i = 0; i < parseList.Count; i++) { TextFieldAttribute attr = attributes[i]; if (attr != null) { string strVal = Truncate(parseList[i], attr.Size); // If there is a custom formatter, then use that to deserialize the string, otherwise use the default .NET behvavior. object fieldObj = attr.Formatter != null?attr.Formatter.Deserialize(strVal) : Convert.ChangeType(strVal, attr.GetNativeType()); // Depending on whether the TargetType is a class or struct, you have to populate the fields differently if (_type.IsValueType) { AssignToStruct(returnStruct, fieldObj, attr.Member); } else { AssignToClass(returnObj, fieldObj, attr.Member); } } } // If this was a value type, need to do a little more magic so can be returned properly if (_type.IsValueType) { object tempObj = (object)returnStruct; returnObj = (TTargetType)tempObj; } return(returnObj); }
protected TextSerializer() { // Get the Reflection type for the Generic Argument _type = GetType().GetGenericArguments()[0]; // Double check that the TextSerializableAttribute has been attached to the TargetType object[] serAttrs = _type.GetCustomAttributes(typeof(TextSerializableAttribute), false); if (serAttrs.Length == 0) { throw new TextSerializationException("TargetType must have a TextSerializableAttribute attached"); } // Get all the public properties and fields on the class MemberInfo[] members = _type.GetMembers(BindingFlags.Instance | BindingFlags.Public | BindingFlags.GetField | BindingFlags.GetProperty); foreach (MemberInfo member in members) { // Check to see if they've marked up this field/property with the attribute for serialization object[] fieldAttrs = member.GetCustomAttributes(typeof(TextFieldAttribute), false); if (fieldAttrs.Length > 0) { Type memberType; if (member is FieldInfo) { memberType = ((FieldInfo)member).FieldType; } else if (member is PropertyInfo) { memberType = ((PropertyInfo)member).PropertyType; } else { throw new TextSerializationException("Invalid MemberInfo type encountered"); } TextFieldAttribute textField = (TextFieldAttribute)fieldAttrs[0]; // Check for the AllowedValues Attribute and if it's there, store away the values into the other holder attribute object[] allowedAttrs = member.GetCustomAttributes(typeof(AllowedValuesAttribute), false); if (allowedAttrs.Length > 0) { AllowedValuesAttribute allowedAttr = (AllowedValuesAttribute)allowedAttrs[0]; textField.AllowedValues = allowedAttr.AllowedValues; } // If they don't override the name in the Attribute, use the MemberInfo name if (string.IsNullOrEmpty(textField.Name)) { textField.Name = member.Name; } textField.Member = member; _textFields.Add(textField.Position, textField); } } }
/// <summary>Serializes a single TargetType object into a properly formatted record string.</summary> /// <param name="obj">Object to serialize</param> /// <returns>Record string</returns> /// <exception cref="TextSerializationException">Thrown if an invalid class member is encountered.</exception> public string Serialize(TTargetType obj) { // First go through the object and get string representations of all the fields List <string> fieldList = new List <string>(); for (int i = 0; i < _textFields.Count; i++) { TextFieldAttribute attr = _textFields[i]; object objValue; // Get the object from the field if (attr.Member is PropertyInfo) { objValue = ((PropertyInfo)attr.Member).GetValue(obj, null); } else if (attr.Member is FieldInfo) { objValue = ((FieldInfo)attr.Member).GetValue(obj); } else { throw new TextSerializationException("Invalid MemberInfo type encountered"); } // Get the string representation for the object. If there is a custom formatter for this field, then // use that, otherwise use the default ToString behavior. string str = attr.Formatter != null?attr.Formatter.Serialize(objValue) : objValue.ToString(); // Truncate the string if required fieldList.Add(Truncate(str, attr.Size)); } // Now that all the strings are collected, put them together into a record string depending on the // type of serializer that this is. return(FormatOutput(fieldList)); }