예제 #1
0
        /// <summary>
        /// Get enumerable text objects beginning at the current position in the stream.
        /// </summary>
        /// <param name="textReader">Stream to read</param>
        /// <param name="t">Type of class objects to read into.</param>
        /// <returns>
        ///   Enumerable list of class object. DO NOT close stream until after the
        ///   enumerable list has been evaluated.
        /// </returns>
        private IEnumerable Deserialize(TextReader textReader, Type t)
        {
            var sp = new SerializerProperties(t, null, Culture);

            using (var reader = new CsvReader(textReader))
            {
                var list       = (IList)Activator.CreateInstance(typeof(List <>).MakeGenericType(t));
                var headers    = reader.ReadRecord();
                var properties = sp.ReOrderPropertiesByHeaders(headers);
                while (!reader.EndOfFile)
                {
                    var index   = 0;
                    var nuClass = Activator.CreateInstance(t);
                    foreach (var field in reader.ReadField())
                    {
                        var pa = properties[index];
                        // CSV cannot detect difference between "" and null, so we opt for null to support nullable types.
                        pa.SetValue(nuClass, field.Length == 0 ? null : field);
                        index++;
                    }

                    if (index > 0)
                    {
                        yield return(nuClass);
                    }
                }

                yield break;
            }
        }
예제 #2
0
        /// <summary>
        /// Serializes a single enumerable object into a single CSV document into the
        /// specified Stream. There are NO limits to the number of records written to the
        /// stream. There is no caching or buffering. Individual values are formatted and
        /// written to the stream immediately.
        /// </summary>
        /// <param name="textwriter">
        ///   Open stream to write to. Note: stream is not closed and stream pointer is not
        ///   reset to beginning in order to potentially perform further processing.
        /// </param>
        /// <param name="items">Enumerable list of items to write.</param>
        public void Serialize(TextWriter textwriter, IEnumerable items)
        {
            var sp = new SerializerProperties(items, null, Culture);

            using (var writer = new CsvWriter(textwriter))
            {
                // Write header record
                foreach (var p in sp.Properties)
                {
                    writer.WriteField(p.Header);
                }

                writer.WriteEOL();

                // Write records
                while (sp.ItemEnumerator.MoveNext())
                {
                    foreach (var p in sp.Properties)
                    {
                        writer.WriteField(p.GetValue(sp.ItemEnumerator.Current));
                    }

                    writer.WriteEOL();
                }
            }
        }
예제 #3
0
        /// <summary>
        /// Create new Property Attribute object with all necessary values pre-computed for fast usability.
        /// </summary>
        /// <param name="p">Property info to use to set values.</param>
        /// <param name="ci">Culture to use for localization of header</param>
        private PropertyAttribute(PropertyInfo p, CultureInfo ci)
        {
            Name         = p.Name;
            PropertyType = p.PropertyType;
            CellType     = p.PropertyType.IsGenericType ? p.PropertyType.GenericTypeArguments[0] : p.PropertyType;
            IsNullable   = p.PropertyType.IsGenericType;
            GetValue     = (o) => p.GetValue(o);
            SetValue     = (o, v) => p.SetValue(o, Cast.To(p.PropertyType, v));

            if (CellType == typeof(bool))
            {
                GetValue = (o) => p.GetValue(o)?.ToString();  // Excel uses TRUE/FALSE. We like True/False
            }
            else if (CellType == typeof(string))
            {
                GetValue = (o) => p.GetValue(o)?.ToString().AppendSp();
                SetValue = (o, v) => p.SetValue(o, v.ToString().TrimSp());
            }
            else if (CellType == typeof(char))  // EPPlus assumes primitive types are always numbers!
            {
                GetValue = (o) => p.GetValue(o)?.ToString().AppendSp();
                SetValue = (o, v) => p.SetValue(o, v?.ToString()?[0]);
            }

            XlColumnAttribute a = p.GetCustomAttribute <XlColumnAttribute>(true);

            if (a == null)
            {
                Header = LocalizedStrings.GetString(p.Name, null, ci);
            }
            else
            {
                if (ci.Name != string.Empty && a.TranslateData)
                {
                    if (CellType == typeof(string) || CellType == typeof(bool))
                    {
                        GetValue = (o) =>
                        {
                            var v = p.GetValue(o);
                            if (v == null)
                            {
                                return(null);
                            }
                            return(LocalizedStrings.GetString(v.ToString(), ci));
                        };
                        SetValue = (o, v) =>
                        {
                            if (!string.IsNullOrWhiteSpace(v as string))
                            {
                                p.SetValue(o, Cast.To(p.PropertyType, LocalizedStrings.ReverseLookup(v.ToString(), ci)));
                            }
                        };
                    }
                    else if (CellType.IsEnum)
                    {
                        // Note: ExcelSerializer restricts values to a limited set of choices.
                        var vals       = Enum.GetValues(CellType);
                        var elookup    = new Dictionary <Enum, string>(vals.Length);
                        var erevlookup = new Dictionary <string, Enum>(vals.Length);
                        foreach (Enum e in vals)
                        {
                            var s = SerializerProperties.LocalizedEnumName(e, ci);
                            elookup.Add(e, s);
                            erevlookup.Add(s, e);
                        }

                        GetValue = (o) =>
                        {
                            var v = p.GetValue(o);
                            if (v == null)
                            {
                                return(null);
                            }
                            return(elookup[(Enum)v]);
                        };
                        SetValue = (o, v) =>
                        {
                            if (!string.IsNullOrWhiteSpace(v as string))
                            {
                                p.SetValue(o, erevlookup[(string)v]);
                            }
                        };
                    }
                }

                Header        = LocalizedStrings.GetString(a.Id, p.Name, ci);
                Format        = a.Format;
                Frozen        = a.Frozen;
                HasFilter     = a.HasFilter;
                Justification = a.Justification;
                Hidden        = a.Hidden;
                TranslateData = a.TranslateData;
                MaxWidth      = a.MaxWidth;

                // Format styling may contain 2 comma delimited fields. The first field contains code char + int
                // where the int represents the number of digits after the decimal (aka precision). The optional 2nd
                // field contains the units string(including leading and trailing whitespace). However if the 2nd
                // field contains an integer, it is used as a relative column index to the column value containing the units.
                if (!string.IsNullOrWhiteSpace(Format) && (Format[0] == 'f' || Format[0] == 'F' ||
                                                           Format[0] == 'n' || Format[0] == 'N' ||
                                                           Format[0] == 'c' || Format[0] == 'C'))
                {
                    var e = Format.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                    if (e.Length > 1 && int.TryParse(e[1].Trim(), out var index))
                    {
                        RelUnitsIndex = index;
                        Format        = e[0];
                    }
                }
            }
        }