public ValueContext(Type valueType) { Type = valueType; Properties = new Dictionary <string, PropertyInfo>(); if (valueType != typeof(string) && typeof(IList).IsAssignableFrom(valueType)) { // Find the type our collection contains, which we'll use this to create instances of any Structs in this collection if (valueType.IsGenericType) { // If generic collection, what's our T? CollectedType = valueType.GetGenericArguments().FirstOrDefault(); // Hope that this is a generic collection of some kind Value = Activator.CreateInstance(valueType); } else if (valueType.IsArray) { // If array, what's our T[]? CollectedType = valueType.GetElementType(); // We treat arrays differently, because they're ILists but they throw when .Add() is called // We'll back this array with a List<T> and call .ToArray() later Value = Activator.CreateInstance(typeof(List <>).MakeGenericType(CollectedType)); } else { throw new ArgumentException($"{valueType} must be an IList that is either an array or generic collection", nameof(valueType)); } } else { // Find our public properties foreach (PropertyInfo property in valueType.GetProperties(BindingFlags.Instance | BindingFlags.Public)) { if (property.GetCustomAttribute <XmlRpcIgnoreAttribute>() != null) { continue; } XmlRpcMemberAttribute xmlRpcMember = property.GetCustomAttribute <XmlRpcMemberAttribute>(); if (xmlRpcMember != null) { Properties.Add(xmlRpcMember.Name, property); } else { Properties.Add(property.Name, property); } } Value = Activator.CreateInstance(valueType); } }
public static async Task WriteXmlRpcObjectAsync(this XmlWriter writer, object target) { if (target == null) { return; } // Built-In Types Table (C# Reference) // https://msdn.microsoft.com/en-us/library/ya5y69ds.aspx if (target is bool) { // Convert booleans to "1" or "0" writer.WriteXmlRpcValue("boolean", (bool)target ? "1" : "0"); } else if (target is byte) { // Unsigned throw new ArgumentException("target is byte, use sbyte instead", nameof(target)); } else if (target is sbyte) { // Signed 8-bit writer.WriteXmlRpcValue("i4", Convert.ToString(Convert.ToInt32(target))); } else if (target is char) { // Unicode 16-bit writer.WriteXmlRpcValue("string", Convert.ToString(target)); } else if (target is decimal) { // Data loss, use double throw new ArgumentException("target is decimal, conversion to double may result in loss of precision", nameof(target)); } else if (target is double) { writer.WriteXmlRpcValue("double", Convert.ToString(Convert.ToDouble(target), CultureInfo.InvariantCulture)); } else if (target is float) { // 32-bit, convert to double writer.WriteXmlRpcValue("double", Convert.ToString(Convert.ToDouble(target), CultureInfo.InvariantCulture)); } else if (target is int) { writer.WriteXmlRpcValue("i4", Convert.ToString(Convert.ToInt32(target))); } else if (target is uint) { // Unsigned throw new ArgumentException("target is uint, use signed 32-bit integer instead", nameof(target)); } else if (target is long) { // Signed 64-bit throw new ArgumentException("target is long, use signed 32-bit integer instead", nameof(target)); } else if (target is ulong) { // Unsigned throw new ArgumentException("target is ulong, use signed 32-bit integer instead", nameof(target)); } else if (target is short) { // Signed 16-bit writer.WriteXmlRpcValue("i4", Convert.ToString(Convert.ToInt32(target))); } else if (target is ushort) { // Unsigned 16-bit throw new ArgumentException("target is ushort, use short instead", nameof(target)); } else if (target is string) { await writer.WriteXmlRpcValueAsync("string", Convert.ToString(target)); } else if (target is DateTime) { writer.WriteXmlRpcValue("dateTime.iso8601", ((DateTime)target).ToString("yyyyMMdd'T'HH':'mm':'ss", CultureInfo.InvariantCulture)); } else if (target is byte[]) { // Base64 await writer.WriteXmlRpcValueAsync("base64", Convert.ToBase64String((byte[])target)); } else if (target is IEnumerable) { writer.WriteStartElement("value"); writer.WriteStartElement("array"); writer.WriteStartElement("data"); foreach (object item in (IEnumerable)target) { await writer.WriteXmlRpcObjectAsync(item); } writer.WriteEndElement(); writer.WriteEndElement(); writer.WriteEndElement(); } else { writer.WriteStartElement("value"); writer.WriteStartElement("struct"); foreach (PropertyInfo property in target.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public)) { MethodInfo getMethod = property.GetGetMethod(); if (getMethod != null && property.GetCustomAttribute <XmlRpcIgnoreAttribute>() == null) { object propertyValue = getMethod.Invoke(target, null); // Don't try to serialize a null value // We won't include this <member> at all if (propertyValue == null) { continue; } writer.WriteStartElement("member"); XmlRpcMemberAttribute xmlRpcMember = property.GetCustomAttribute <XmlRpcMemberAttribute>(); // In death, a member of Project Struct has a name writer.WriteStartElement("name"); writer.WriteString(xmlRpcMember != null ? xmlRpcMember.Name : property.Name); writer.WriteEndElement(); await writer.WriteXmlRpcObjectAsync(propertyValue); writer.WriteEndElement(); } } writer.WriteEndElement(); writer.WriteEndElement(); } }