Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- static public class DataImporter
- {
- private class PropertyData
- {
- public PropertyInfo Prop { get; set; }
- public TypeConverter Converter { get; set; }
- }
- public class StringToListOptions
- {
- public StringToListOptions()
- {
- SplitLines = (input) => input.Split('\n');
- SplitProperties = (input) => input.Split(',');
- PropertyProcessingChain = new List<Func<string, string>>()
- {
- (input) => input.Trim()
- };
- }
- /// <summary>
- /// A function that splits the source data in to individual lines.
- /// </summary>
- public Func<string, string[]> SplitLines { get; set; }
- /// <summary>
- /// A function that splits a source line in to individual properties.
- /// </summary>
- public Func<string, string[]> SplitProperties { get; set; }
- /// <summary>
- /// A list of Func<string, string> that accepts a string, modifies it, then return it. Defaults to "(input) => input.Trim()".
- /// </summary>
- internal List<Func<string, string>> PropertyProcessingChain { get; }
- /// <summary>
- /// Clears the list of property processors.
- /// </summary>
- public void ClearPropertyProcessingChain()
- {
- PropertyProcessingChain.Clear();
- }
- /// <summary>
- /// Adds a new Func<string, string> that accepts a string, modifies it, and returns it.
- /// </summary>
- public void AddPropertyProcessor(Func<string, string> processor)
- {
- PropertyProcessingChain.Add(processor);
- }
- }
- /// <summary>
- /// Converts a string in to a List<T> by splitting it in to lines, and lines in to properties.
- /// </summary>
- /// <param name="input">
- /// The string to convert.
- /// </param>
- /// <param name="properties">
- /// A list of property to convert and map to T, in the order they appear in the input string,
- /// in the format "t => new {t.Property1, t.Property2}"
- /// </param>
- public static List<T> ConvertToList<T>(this string input,
- Expression<Func<T, object>> fields) where T : new()
- {
- return ConvertToList(input, fields, new StringToListOptions());
- }
- /// <summary>
- /// Converts a string in to a List<T> by splitting it in to lines, and lines in to properties.
- /// </summary>
- /// <param name="input">
- /// The string to convert
- /// </param>
- /// <param name="properties">
- /// A list of property to convert and map to T, in the order they appear in the input string,
- /// in the format "t => new {t.Property1, t.Property2}"
- /// </param>
- /// <param name="options">
- /// Options that control how the input string is parsed.
- /// </param>
- public static List<T> ConvertToList<T>(this string input,
- Expression<Func<T, object>> properties,
- StringToListOptions options) where T : new()
- {
- string[] propertyList = GetPropertyNamesFromExpression();
- var targetType = typeof(T);
- var propertyData = FindPropertyInfo();
- var list = new List<T>();
- var rawSource = options.SplitLines(input);
- foreach (var rawLine in rawSource)
- {
- var item = new T();
- list.Add(item);
- var rawFields = options.SplitProperties(rawLine);
- if (propertyData.Count != rawFields.Length)
- {
- throw new ArgumentException("String data does not contain the same number of fields as the list of fields.", nameof(input));
- }
- int propertyIndex = 0;
- foreach (var field in propertyData)
- {
- var rawField = rawFields[propertyIndex];
- foreach (var processor in options.PropertyProcessingChain)
- {
- rawField = processor(rawField);
- }
- field.Prop.SetValue(item, field.Converter.ConvertFromString(rawField));
- propertyIndex++;
- }
- }
- return list;
- string[] GetPropertyNamesFromExpression()
- {
- try
- {
- return ((NewExpression)properties.Body).Arguments.Select(argument => ((MemberExpression)argument).Member.Name).ToArray();
- }
- catch (Exception)
- {
- throw new ArgumentException($"Syntax Error: '{nameof(properties)}' must be an expression that returns an anonmous type containing a list of properties, e.g.: t => new {{t.Property1, t.Property2}}", nameof(properties));
- }
- }
- List<PropertyData> FindPropertyInfo()
- {
- var data = new List<PropertyData>();
- foreach (var field in propertyList)
- {
- var item = new PropertyData();
- data.Add(item);
- item.Prop = targetType.GetProperty(field, BindingFlags.Public | BindingFlags.Instance);
- item.Converter = TypeDescriptor.GetConverter(item.Prop.PropertyType);
- }
- return data;
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement