using System; using System.Linq; using System.Reflection; using Fasterflect; namespace LeafWeb.Core.Services { public static class ParsedObjectFactory where T : new() { private static PropertyInfo[] GetProperties() { var propertyInfos = typeof(T).Properties(); return propertyInfos.Where(p => p.HasAttribute()).ToArray(); } /// /// Create an object type T filling properties from the given title values /// /// Colon separated title: values public static T Create(string[] titleValues) { var properties = GetProperties(); var obj = new T(); // take each of the for (var index = 0; index < titleValues.Length; index++) { PropertyInfo property = null; string value = null; var lineNumber = index + 1; var row = titleValues[index]; var split = row.Split(':'); if (split.Length > 1) { // handles case for "Title : Value" var title = split[0].Trim(); value = split[1].Trim(); property = properties .FirstOrDefault(p => p.Attribute().IsTitleMatch(title)); } if (property == null) { // handles case for row number, i.e. "Value" value = row.Trim(); property = properties .FirstOrDefault(p => p.Attribute().IsPositionMatch(lineNumber)); } if (property != null) { object convertedVal; if (!TryConvertValue(property, value, out convertedVal)) throw new ParseException(string.Format("Cannot convert value '{0}' for {1} at line number {2}", value, property.Name, lineNumber)); property.Set(obj, convertedVal); } } return obj; } public static T[] Create(string[] titles, string[][] valueArrays) { var properties = GetProperties(); var objs = new T[valueArrays.Length]; for (var vIndex = 0; vIndex < valueArrays.Length; vIndex++) { var obj = new T(); var values = valueArrays[vIndex]; for (var tIndex = 0; tIndex < titles.Length; tIndex++) { var title = titles[tIndex]; var value = values[tIndex]; var position = tIndex + 1; if (IsMissingValue(value)) continue; var property = MatchProperty(properties, title, position); if (property != null) { object convertedVal; if (!TryConvertValue(property, value, out convertedVal)) throw new ParseException(string.Format("Cannot convert value '{0}' for {1} in position {2}", value, property.Name, position)); property.Set(obj, convertedVal); } } objs[vIndex] = obj; } return objs; } public static T Create(Tuple[] titleValues) { var properties = GetProperties(); var obj = new T(); for (var index = 0; index < titleValues.Length; index++) { var item = titleValues[index]; var position = index + 1; var title = item.Item1.Trim(); var value = item.Item2.Trim(); if (IsMissingValue(value)) continue; var property = MatchProperty(properties, title, position); if (property != null) { object convertedVal; if (!TryConvertValue(property, value, out convertedVal)) throw new ParseException(string.Format("Cannot convert value '{0}' for {1} in position {2}", value, property.Name, position)); property.Set(obj, convertedVal); } } return obj; } private static bool IsMissingValue(string value) { return string.IsNullOrEmpty(value) || value == "NA" || value == "-9999"; } private static PropertyInfo MatchProperty(PropertyInfo[] properties, string title, int position) { var property = properties .FirstOrDefault(p => p.Attribute().IsTitleMatch(title)); if (property == null) { property = properties .FirstOrDefault(p => p.Attribute().IsPositionMatch(position)); } return property; } private static bool TryConvertValue(PropertyInfo property, object value, out object convertedValue) { try { // http://stackoverflow.com/questions/3531318/convert-changetype-fails-on-nullable-types var t = Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType; convertedValue = Convert.ChangeType(value, t); } catch (Exception) { convertedValue = null; return false; } return true; } } }