public override object Deserialize(TextReader tr) { if (tr != null) { // Normalize the text before parsing it tr = TextUtil.Normalize(tr, SerializationContext); // Create a lexer for our text stream iCalLexer lexer = new iCalLexer(tr); iCalParser parser = new iCalParser(lexer); // Get our serialization context ISerializationContext ctx = SerializationContext; // Parse the component! ICalendarProperty p = parser.property(ctx, null); // Close our text stream tr.Close(); // Return the parsed property return(p); } return(null); }
/// <summary> /// Removes the value from the list of properties. /// </summary> /// <param name="value">The value to remove.</param> /// <returns>True if the value was successfully removed, false otherwise.</returns> virtual public bool Remove(T value) { if (m_PropertyList.ContainsKey(m_PropertyName)) { // Search for a property that contains this value. ICalendarProperty property = m_PropertyList .AllOf(m_PropertyName) .Where(p => p.ContainsValue(value)) .FirstOrDefault(); // If we found a property that contains this value, then let's remove it. if (property != null) { // Remove the value property.RemoveValue(value); // If this property doesn't contain any more values, then // let's also remove the property itself. if (property.Values.Count() == 0) { m_PropertyList.Remove(property); } return(true); } } return(false); }
public void Insert(int index, T item) { if (IsReadOnly) { throw new NotSupportedException(); } if (index < 0 || index >= Count) { throw new ArgumentOutOfRangeException("index"); } bool isList; int propertyIndex, indexInProperty; ICalendarProperty p = PropertyForIndex(index, out isList, out propertyIndex, out indexInProperty); if (p != null) { if (isList) { ((IList <object>)p.Value).Insert(indexInProperty, item); } else { ICalendarProperty newProperty = p.Copy <ICalendarProperty>(); newProperty.Value = item; m_PropertyList.Insert(propertyIndex, newProperty); } } }
public void RemoveAt(int index) { if (IsReadOnly) { throw new NotSupportedException(); } if (index < 0 || index >= Count) { throw new ArgumentOutOfRangeException("index"); } bool isList; int propertyIndex, indexInProperty; ICalendarProperty p = PropertyForIndex(index, out isList, out propertyIndex, out indexInProperty); if (p != null) { if (isList) { ((IList <object>)p.Value).RemoveAt(indexInProperty); } else { m_PropertyList.RemoveAt(propertyIndex); } } }
private void MoveNextProperty() { m_CurrentListEnumerator = null; while (m_PropertyIndex + 1 < m_PropertyList.Count) { ICalendarProperty p = m_PropertyList[++m_PropertyIndex]; if (string.Equals(p.Name, m_PropertyName)) { object value = p.Value; if (value is IList <object> ) { IList <T> list = new List <T>(); foreach (object obj in (IList <object>)value) { if (obj is T) { list.Add((T)obj); } } m_CurrentListEnumerator = list.GetEnumerator(); return; } else if (value is T) { m_CurrentListEnumerator = new SingleValueEnumerator <T>((T)value); return; } } } }
public override void CopyFrom(ICopyable obj) { base.CopyFrom(obj); ICalendarProperty p = obj as ICalendarProperty; if (p != null) { // Copy/clone the object if possible (deep copy) if (p.Values is ICopyable) { SetValue(((ICopyable)p.Values).Copy <object>()); } else if (p.Values is ICloneable) { SetValue(((ICloneable)p.Values).Clone()); } else { SetValue(p.Values); } // Copy parameters foreach (ICalendarParameter parm in p.Parameters) { AddParameter(parm.Copy <ICalendarParameter>()); } } }
public override void CopyFrom(ICopyable obj) { base.CopyFrom(obj); ICalendarProperty p = obj as ICalendarProperty; if (p != null) { if (p.Value is ICopyable) { Value = ((ICopyable)p.Value).Copy <object>(); } else if (p.Value is ICloneable) { Value = ((ICloneable)p.Value).Clone(); } else { Value = p.Value; } // Copy parameters foreach (ICalendarParameter parm in p.Parameters) { AddChild(parm.Copy <ICalendarParameter>()); } } }
public int IndexOf(T item) { bool isList; int itemIndex, indexInProperty; ICalendarProperty p = PropertyForItem(item, out isList, out itemIndex, out indexInProperty); return(itemIndex); }
protected void SerializeValue(ISerializerFactory sf, ICalendarProperty prop, Type valueType, object v, StringBuilder result) { // Get a serializer to serialize the property's value. // If we can't serialize the property's value, the next step is worthless anyway. IStringSerializer valueSerializer = sf.Build(valueType, SerializationContext) as IStringSerializer; if (valueSerializer != null) { // Iterate through each value to be serialized, // and give it a property (with parameters). // FIXME: this isn't always the way this is accomplished. // Multiple values can often be serialized within the // same property. How should we fix this? // NOTE: // We Serialize the property's value first, as during // serialization it may modify our parameters. // FIXME: the "parameter modification" operation should // be separated from serialization. Perhaps something // like PreSerialize(), etc. string value = valueSerializer.SerializeToString(v); // Get the list of parameters we'll be serializing ICalendarParameterCollection parameterList = prop.Parameters; if (v is ICalendarDataType) { parameterList = ((ICalendarDataType)v).Parameters; } StringBuilder sb = new StringBuilder(prop.Name); if (parameterList.Any()) { // Get a serializer for parameters IStringSerializer parameterSerializer = sf.Build(typeof(ICalendarParameter), SerializationContext) as IStringSerializer; if (parameterSerializer != null) { // Serialize each parameter List <string> parameters = new List <string>(); foreach (ICalendarParameter param in parameterList) { parameters.Add(parameterSerializer.SerializeToString(param)); } // Separate parameters with semicolons sb.Append(";"); sb.Append(string.Join(";", parameters.ToArray())); } } sb.Append(":"); sb.Append(value); result.Append(TextUtil.WrapLines(sb.ToString())); } }
protected void SerializeValue(ISerializerFactory sf, ICalendarProperty prop, Type valueType, object v, StringBuilder result) { // Get a serializer to serialize the property's value. // If we can't serialize the property's value, the next step is worthless anyway. IStringSerializer valueSerializer = sf.Build(valueType, SerializationContext) as IStringSerializer; if (valueSerializer != null) { // Iterate through each value to be serialized, // and give it a property (with parameters). // FIXME: this isn't always the way this is accomplished. // Multiple values can often be serialized within the // same property. How should we fix this? // NOTE: // We Serialize the property's value first, as during // serialization it may modify our parameters. // FIXME: the "parameter modification" operation should // be separated from serialization. Perhaps something // like PreSerialize(), etc. string value = valueSerializer.SerializeToString(v); // Get the list of parameters we'll be serializing ICalendarParameterCollection parameterList = prop.Parameters; if (v is ICalendarDataType) parameterList = ((ICalendarDataType)v).Parameters; StringBuilder sb = new StringBuilder(prop.Name); if (parameterList.Any()) { // Get a serializer for parameters IStringSerializer parameterSerializer = sf.Build(typeof(ICalendarParameter), SerializationContext) as IStringSerializer; if (parameterSerializer != null) { // Serialize each parameter List<string> parameters = new List<string>(); foreach (ICalendarParameter param in parameterList) { parameters.Add(parameterSerializer.SerializeToString(param)); } // Separate parameters with semicolons sb.Append(";"); sb.Append(string.Join(";", parameters.ToArray())); } } sb.Append(":"); sb.Append(value); result.Append(TextUtil.WrapLines(sb.ToString())); } }
public T this[int index] { get { bool isList; int propertyIndex, indexInProperty; ICalendarProperty p = PropertyForIndex(index, out isList, out propertyIndex, out indexInProperty); if (p != null) { object value; if (isList) { value = ((IList <object>)p.Value)[indexInProperty]; } else { value = p.Value; } if (value is T) { return((T)value); } } return(default(T)); } set { bool isList; int propertyIndex, indexInProperty; ICalendarProperty p = PropertyForIndex(index, out isList, out propertyIndex, out indexInProperty); if (p != null) { object oldValue; if (isList) { oldValue = ((IList <object>)p)[indexInProperty]; ((IList <object>)p)[indexInProperty] = value; } else { oldValue = p.Value; p.Value = value; } T old = oldValue is T ? (T)oldValue : default(T); // FIXME: Call OnItemAdded()/OnItemRemoved() here? } } }
virtual public bool GetPropertyAllowsMultipleValues(object obj) { ICalendarProperty p = obj as ICalendarProperty; if (p != null && p.Name != null) { string name = p.Name.ToUpper(); if (_PropertyMap.ContainsKey(name)) { PropertyMapping m = _PropertyMap[name]; return(m.AllowsMultipleValuesPerProperty); } } return(false); }
protected override IValidationResultCollection ValidateProperty(ICalendarProperty p) { ValidationResultCollection result = new ValidationResultCollection(ResourceManager); if (p != null) { result.Passed = true; // Get the escaped value for this property. // This is stored during deserialization when // SerializationSettings.StoreExtraSerializationData is true. object escapedValue = p.GetService("EscapedValue"); List<string> values = new List<string>(); if (escapedValue is string) values.Add((string)escapedValue); else if (escapedValue is IList<string>) values.AddRange((IList<string>)escapedValue); // Validate the encoding EncodableDataType dt = new EncodableDataType(); dt.AssociatedObject = p; EncodableDataTypeValidation validation = new EncodableDataTypeValidation(ResourceManager, dt); result.Add(validation.Validate()); foreach (string value in values) { // Find single commas if (Regex.IsMatch(value, @"(?<!\\),")) { Error(result, "textEscapeCommasError", p.Line, p.Column, p.Name); } // Find single semicolons if (Regex.IsMatch(value, @"(?<!\\);")) { Error(result, "textEscapeSemicolonsError", p.Line, p.Column, p.Name); } // Find backslashes that are not escaped if (Regex.IsMatch(value, @"\\([^\\nN;,])")) { Error(result, "textEscapeBackslashesError", p.Line, p.Column, p.Name); } } } return result; }
public bool Remove(T item) { bool isList; int itemIndex, indexInProperty; ICalendarProperty p = PropertyForItem(item, out isList, out itemIndex, out indexInProperty); if (p != null) { if (isList) { ((IList <object>)p.Value).RemoveAt(indexInProperty); return(true); } else { return(m_PropertyList.Remove(p)); } } return(false); }
virtual public Type GetPropertyMapping(object obj) { ICalendarProperty p = obj as ICalendarProperty; if (p != null && p.Name != null) { string name = p.Name.ToUpper(); if (_PropertyMap.ContainsKey(name)) { PropertyMapping m = _PropertyMap[name]; if (m.Resolver != null) { return(m.Resolver(p)); } else { return(m.ObjectType); } } } return(null); }
protected override IValidationResultCollection ValidateProperty(ICalendarProperty p) { ValidationResultCollection result = new ValidationResultCollection(ResourceManager); if (p != null) { result.Passed = true; // FIXME: is it valid to have an empty URI? if (p.Value != null && !(p.Value is Uri)) { try { Uri uri = new Uri(p.Value.ToString()); Error(result, "invalidUriFormatError", p.Line, p.Column, p.Value, "An unknown error occurred."); } catch (Exception ex) { Error(result, "invalidUriFormatError", p.Line, p.Column, p.Value, ex.Message); } } } return result; }
public override object Deserialize(TextReader tr) { ICalendarProperty p = SerializationContext.Peek() as ICalendarProperty; if (p != null) { // Get a serializer factory to deserialize the contents of this list ISerializerFactory sf = GetService <ISerializerFactory>(); object listObj = Activator.CreateInstance(_ObjectType); if (listObj != null) { // Get a serializer for the inner type IStringSerializer stringSerializer = sf.Build(_InnerType, SerializationContext) as IStringSerializer;; if (stringSerializer != null) { // Deserialize the inner object string value = tr.ReadToEnd(); object objToAdd = stringSerializer.Deserialize(new StringReader(value)); // If deserialization failed, pass the string value // into the list. if (objToAdd == null) { objToAdd = value; } if (objToAdd != null) { // FIXME: cache this MethodInfo mi = _ObjectType.GetMethod("Add"); if (mi != null) { // Determine if the returned object is an IList<ObjectType>, // rather than just an ObjectType. if (objToAdd is IEnumerable && objToAdd.GetType().Equals(typeof(List <>).MakeGenericType(_InnerType))) { // Deserialization returned an IList<ObjectType>, instead of // simply an ObjectType. So, let's enumerate through the // items in the list and add them individually to our // list. foreach (object innerObj in (IEnumerable)objToAdd) { mi.Invoke(listObj, new object[] { innerObj }); } } else { // Add the object to the list mi.Invoke(listObj, new object[] { objToAdd }); } return(listObj); } } } } } return(null); }
protected override IValidationResultCollection ValidateProperty(ICalendarProperty p) { ValidationResultCollection result = new ValidationResultCollection(ResourceManager); if (p != null) { result.Passed = true; // Ensure that the date-time (or date) value is formatted properly bool hasTime = true; if (p.Parameters.ContainsKey("VALUE") && string.Equals(p.Parameters["VALUE"].Values[0], "DATE")) { hasTime = false; } if (p.Value is string) { // If the value is a string value, then it didn't // get properly parsed into an IDateTime value. string value = p.Value.ToString(); string dateOnlyPattern = @"^\d{8}$"; string fullPattern = @"^\d{8}T\d{6}(Z)?$"; if (hasTime && Regex.IsMatch(value, dateOnlyPattern)) Error(result, "missingValueDateError", p.Line, p.Column, value); else if (!hasTime && Regex.IsMatch(value, fullPattern)) Error(result, "valueDateIncorrectlyUsedError", p.Line, p.Column, value); else if (hasTime) Error(result, "invalidDateTimeFormatError", p.Line, p.Column, value); else Error(result, "invalidDateFormatError", p.Line, p.Column, value); } else if (p.Value is IDateTime) { // Validate date/time ranges on the valid date/time value. IDateTime dt = (IDateTime)p.Value; if (// The maximum representable date/time on .NET systems dt.Value.Equals(DateTime.MinValue) || dt.Value.Equals(DateTime.MaxValue) || // The maximum representable date/time on 32-bit Unix systems. dt.Value < new DateTime(1901, 12, 13) || dt.Value > new DateTime(2038, 1, 19) || // Representable date/times on SQL Server 200X dt.Value < new DateTime(1753, 1, 1) || dt.Value > new DateTime(2079, 6, 6)) { Warning(result, "dateOutOfRangeError", p.Line, p.Column, p.Value); } else { // Ensure that, if a time zone was provided on the date-time property, // that the corresponding time zone is contained in the calendar. if (dt.TZID != null) { ITimeZone tz = p.iCalendar.GetTimeZone(dt.TZID); if (tz == null) Error(result, "timeZoneNotFoundError", p.Line, p.Column, dt.TZID); } } } } return result; }
public override string SerializeToString(object obj) { ICalendarProperty prop = obj as ICalendarProperty; if (prop != null && prop.Value != null) { // Don't serialize the property if the value is null // Push this object on the serialization context. SerializationContext.Push(prop); IDataTypeMapper mapper = GetService <IDataTypeMapper>(); Type serializedType = mapper.GetPropertyMapping(prop); // Build a list of values that are to be serialized. List <object> objs = new List <object>(); if (!(prop.Value is string) && !(typeof(IEnumerable <string>).IsAssignableFrom(serializedType)) && prop.Value is IEnumerable) { foreach (object v in (IEnumerable)prop.Value) { objs.Add(v); } } else { objs.Add(prop.Value); } // Get a serializer factory that we can use to serialize // the property and parameter values ISerializerFactory sf = GetService <ISerializerFactory>(); StringBuilder result = new StringBuilder(); foreach (object v in objs) { // Get a serializer to serialize the property's value. // If we can't serialize the property's value, the next step is worthless anyway. IStringSerializer valueSerializer = sf.Build(v.GetType(), SerializationContext) as IStringSerializer; if (valueSerializer != null) { // Iterate through each value to be serialized, // and give it a property (with parameters). // FIXME: this isn't always the way this is accomplished. // Multiple values can often be serialized within the // same property. How should we fix this? // NOTE: // We Serialize the property's value first, as during // serialization it may modify our parameters. // FIXME: the "parameter modification" operation should // be separated from serialization. Perhaps something // like PreSerialize(), etc. string value = valueSerializer.SerializeToString(v); // Get the list of parameters we'll be serializing ICalendarParameterList parameterList = prop.Parameters; if (v is ICalendarDataType) { parameterList = ((ICalendarDataType)v).Parameters; } StringBuilder sb = new StringBuilder(prop.Name); if (parameterList.Count > 0) { // Get a serializer for parameters IStringSerializer parameterSerializer = sf.Build(typeof(ICalendarParameter), SerializationContext) as IStringSerializer; if (parameterSerializer != null) { // Serialize each parameter List <string> parameters = new List <string>(); foreach (ICalendarParameter param in parameterList) { parameters.Add(parameterSerializer.SerializeToString(param)); } // Separate parameters with semicolons sb.Append(";"); sb.Append(string.Join(";", parameters.ToArray())); } } sb.Append(":"); sb.Append(value); result.Append(TextUtil.WrapLines(sb.ToString())); } } // Pop the object off the serialization context. SerializationContext.Pop(); return(result.ToString()); } return(null); }
public CalendarProperty(ICalendarProperty other) : this() { CopyFrom(other); }
/// <summary> /// Adds a property to this component. /// </summary> virtual public void AddProperty(ICalendarProperty iCalendarProperty) { iCalendarProperty.Parent = this; Properties.Set(iCalendarProperty.Name, iCalendarProperty); }
public ICalendarProperty property( ISerializationContext ctx, ICalendarPropertyListContainer c ) //throws RecognitionException, TokenStreamException { ICalendarProperty p = null;; IToken n = null; IToken m = null; string v; { switch (LA(1)) { case IANA_TOKEN: { n = LT(1); match(IANA_TOKEN); p = new CalendarProperty(n.getLine(), n.getColumn()); p.Name = n.getText().ToUpper(); break; } case X_NAME: { m = LT(1); match(X_NAME); p = new CalendarProperty(m.getLine(), m.getColumn()); p.Name = m.getText().ToUpper(); break; } default: { throw new NoViableAltException(LT(1), getFilename()); } } } ISerializationProcessor <ICalendarProperty> processor = ctx.GetService(typeof(ISerializationProcessor <ICalendarProperty>)) as ISerializationProcessor <ICalendarProperty>; // Do some pre-processing on the property if (processor != null) { processor.PreDeserialization(p); } if (c != null) { // Add the property to the container, as the parent object(s) // may be needed during deserialization. c.Properties.Add(p); } // Push the property onto the serialization context stack ctx.Push(p); IStringSerializer dataMapSerializer = new DataMapSerializer(ctx); { // ( ... )* for (;;) { if ((LA(1) == SEMICOLON)) { match(SEMICOLON); parameter(ctx, p); } else { goto _loop24_breakloop; } } _loop24_breakloop :; } // ( ... )* match(COLON); v = value(); // Deserialize the value of the property // into a concrete iCalendar data type, // or string value. p.Value = dataMapSerializer.Deserialize(new StringReader(v)); { // ( ... )* for (;;) { if ((LA(1) == CRLF)) { match(CRLF); } else { goto _loop26_breakloop; } } _loop26_breakloop :; } // ( ... )* // Do some final processing on the property: if (processor != null) { processor.PostDeserialization(p); } // Notify that the property has been loaded p.OnLoaded(); // Pop the property off the serialization context stack ctx.Pop(); return(p); }
public ICalendarProperty property( ISerializationContext ctx, ICalendarPropertyListContainer c ) //throws RecognitionException, TokenStreamException { ICalendarProperty p = null;; IToken n = null; IToken m = null; string v; { switch (LA(1)) { case IANA_TOKEN: { n = LT(1); match(IANA_TOKEN); p = new CalendarProperty(n.getLine(), n.getColumn()); p.Name = n.getText().ToUpper(); break; } case X_NAME: { m = LT(1); match(X_NAME); p = new CalendarProperty(m.getLine(), m.getColumn()); p.Name = m.getText().ToUpper(); break; } default: { throw new NoViableAltException(LT(1), getFilename()); } } } ISerializationProcessor <ICalendarProperty> processor = ctx.GetService(typeof(ISerializationProcessor <ICalendarProperty>)) as ISerializationProcessor <ICalendarProperty>; // Do some pre-processing on the property if (processor != null) { processor.PreDeserialization(p); } if (c != null) { // Add the property to the container, as the parent object(s) // may be needed during deserialization. c.Properties.Add(p); } // Push the property onto the serialization context stack ctx.Push(p); IStringSerializer dataMapSerializer = new DataMapSerializer(ctx); { // ( ... )* for (;;) { if ((LA(1) == SEMICOLON)) { match(SEMICOLON); parameter(ctx, p); } else { goto _loop24_breakloop; } } _loop24_breakloop :; } // ( ... )* match(COLON); v = value(); // Deserialize the value of the property // into a concrete iCalendar data type, // a list of concrete iCalendar data types, // or string value. object deserialized = dataMapSerializer.Deserialize(new StringReader(v)); if (deserialized != null) { // Try to determine if this is was deserialized as a *list* // of concrete types. Type targetType = dataMapSerializer.TargetType; Type listOfTargetType = typeof(IList <>).MakeGenericType(targetType); if (listOfTargetType.IsAssignableFrom(deserialized.GetType())) { // We deserialized a list - add each value to the // resulting object. foreach (var item in (IEnumerable)deserialized) { p.AddValue(item); } } else { // We deserialized a single value - add it to the object. p.AddValue(deserialized); } } { // ( ... )* for (;;) { if ((LA(1) == CRLF)) { match(CRLF); } else { goto _loop26_breakloop; } } _loop26_breakloop :; } // ( ... )* // Do some final processing on the property: if (processor != null) { processor.PostDeserialization(p); } // Notify that the property has been loaded p.OnLoaded(); // Pop the property off the serialization context stack ctx.Pop(); return(p); }
public override object Deserialize(TextReader tr) { if (tr != null) { string value = tr.ReadToEnd(); // NOTE: this can deserialize into an IList<string> or simply a string, // depending on the input text. Anything that uses this serializer should // be prepared to receive either a string, or an IList<string>. bool serializeAsList = false; // Determine if we can serialize this property // with multiple values per line. ICalendarObject co = SerializationContext.Peek() as ICalendarObject; if (co is ICalendarProperty) { serializeAsList = GetService <IDataTypeMapper>().GetPropertyAllowsMultipleValues(co); } value = TextUtil.Normalize(value, SerializationContext).ReadToEnd(); // Try to decode the string EncodableDataType dt = null; if (co != null) { dt = new EncodableDataType(); dt.AssociatedObject = co; } List <string> escapedValues = new List <string>(); List <string> values = new List <string>(); int i = 0; if (serializeAsList) { MatchCollection matches = Regex.Matches(value, @"[^\\](,)"); foreach (Match match in matches) { string newValue = dt != null?Decode(dt, value.Substring(i, match.Index - i + 1)) : value.Substring(i, match.Index - i + 1); escapedValues.Add(newValue); values.Add(Unescape(newValue)); i = match.Index + 2; } } if (i < value.Length) { string newValue = dt != null?Decode(dt, value.Substring(i, value.Length - i)) : value.Substring(i, value.Length - i); escapedValues.Add(newValue); values.Add(Unescape(newValue)); } if (co is ICalendarProperty) { // Determine if our we're supposed to store extra information during // the serialization process. If so, let's store the escaped value. ICalendarProperty property = (ICalendarProperty)co; ISerializationSettings settings = GetService <ISerializationSettings>(); if (settings != null && settings.StoreExtraSerializationData) { // Store the escaped value co.SetService("EscapedValue", escapedValues.Count == 1 ? (object)escapedValues[0] : (object)escapedValues); } } // Return either a single value, or the entire list. if (values.Count == 1) { return(values[0]); } else { return(values); } } return(null); }
protected abstract IValidationResultCollection ValidateProperty(ICalendarProperty p);
/// <summary> /// Adds a property to this component. /// </summary> virtual public void AddProperty(ICalendarProperty p) { p.Parent = this; Properties[p.Name] = p; }
/// <summary> /// Adds a property to this component. /// </summary> /// <param name="p">The p.</param> public virtual void AddProperty(ICalendarProperty p) { p.Parent = this; Properties.Set(p.Name, p); }
public override string SerializeToString(object obj) { ICalendarProperty prop = obj as ICalendarProperty; if (prop != null) { // Don't serialize the property if the value is null // Push this object on the serialization context. SerializationContext.Push(prop); IDataTypeMapper mapper = GetService <IDataTypeMapper>(); Type serializedType = mapper.GetPropertyMapping(prop); // Get a serializer factory that we can use to serialize // the property and parameter values ISerializerFactory sf = GetService <ISerializerFactory>(); StringBuilder result = new StringBuilder(); if (prop.Values != null && prop.Values.Any()) { foreach (object v in prop.Values) { // Only serialize the value to a string if it // is non-null. if (v != null) { var valueType = v.GetType(); // Use the determined type of the value if the property // mapping didn't yield any results. if (serializedType == null) { serializedType = valueType; } var genericListOfSerializedType = typeof(IEnumerable <>).MakeGenericType(new Type[] { serializedType }); if (genericListOfSerializedType.IsAssignableFrom(valueType)) { // Serialize an enumerable list of properties foreach (object value in (IEnumerable)v) { SerializeValue(sf, prop, serializedType, value, result); } } else { // Serialize an individual value SerializeValue(sf, prop, valueType, v, result); } } } } else { // If there was no value, then we need to preserve an 'empty' value result.Append(TextUtil.WrapLines(prop.Name + ":")); } // Pop the object off the serialization context. SerializationContext.Pop(); return(result.ToString()); } return(null); }