Custom serialization of an object in .NET

前端 未结 5 2093
盖世英雄少女心
盖世英雄少女心 2020-12-09 06:00

I have a requirement to serialize a list of objects to a flat file. The calls will be something like:

class MyObject
{
    public int x;
    public int y;
           


        
5条回答
  •  北海茫月
    2020-12-09 06:40

    Here is a solution that uses plain old reflection and a custom attribute. It will only serialize/deserialize one item per file, but you could easily add support for multiple items per file.

    // Attribute making it possible
    public class FlatFileAttribute : Attribute
    {
        public int Position { get; set; }
        public int Length { get; set; }
        public Padding Padding { get; set; }
    
        /// 
        /// Initializes a new instance of the  class.
        /// 
        /// Each item needs to be ordered so that 
        /// serialization/deserilization works even if the properties 
        /// are reordered in the class.
        /// Total width in the text file
        /// How to do the padding
        public FlatFileAttribute(int position, int length, Padding padding)
        {
            Position = position;
            Length = length;
            Padding = padding;
        }
    }
    
    public enum Padding
    {
        Left,
        Right
    }
    
    
    /// 
    /// Serializer making the actual work
    /// 
    public class Serializer
    {
        private static IEnumerable GetProperties(Type type)
        {
            var attributeType = typeof(FlatFileAttribute);
    
            return type
                .GetProperties()
                .Where(prop => prop.GetCustomAttributes(attributeType, false).Any())
                .OrderBy(
                    prop =>
                    ((FlatFileAttribute)prop.GetCustomAttributes(attributeType, false).First()).
                        Position);
        }
        public static void Serialize(object obj, Stream target)
        {
            var properties = GetProperties(obj.GetType());
    
            using (var writer = new StreamWriter(target))
            {
                var attributeType = typeof(FlatFileAttribute);
                foreach (var propertyInfo in properties)
                {
                    var value = propertyInfo.GetValue(obj, null).ToString();
                    var attr = (FlatFileAttribute)propertyInfo.GetCustomAttributes(attributeType, false).First();
                    value = attr.Padding == Padding.Left ? value.PadLeft(attr.Length) : value.PadRight(attr.Length);
                    writer.Write(value);
                }
                writer.WriteLine();
            }
        }
    
        public static T Deserialize(Stream source) where T : class, new()
        {
            var properties = GetProperties(typeof(T));
            var obj = new T();
            using (var reader = new StreamReader(source))
            {
                var attributeType = typeof(FlatFileAttribute);
                foreach (var propertyInfo in properties)
                {
                    var attr = (FlatFileAttribute)propertyInfo.GetCustomAttributes(attributeType, false).First();
                    var buffer = new char[attr.Length];
                    reader.Read(buffer, 0, buffer.Length);
                    var value = new string(buffer).Trim();
    
                    if (propertyInfo.PropertyType != typeof(string))
                        propertyInfo.SetValue(obj, Convert.ChangeType(value, propertyInfo.PropertyType), null);
                    else
                        propertyInfo.SetValue(obj, value.Trim(), null);
                }
            }
            return obj;
        }
    
    }
    

    And a small demo:

    // Sample class using the attributes
    public class MyObject
    {
        // First field in the file, total width of 5 chars, pad left
        [FlatFile(1, 5, Padding.Left)]
        public int Age { get; set; }
    
        // Second field in the file, total width of 40 chars, pad right
        [FlatFile(2, 40, Padding.Right)]
        public string Name { get; set; }
    }
    
    private static void Main(string[] args)
    {
        // Serialize an object
        using (var stream = File.OpenWrite("C:\\temp.dat"))
        {
            var obj = new MyObject { Age = 10, Name = "Sven" };
            Serializer.Serialize(obj, stream);
        }
    
        // Deserialzie it from the file
        MyObject readFromFile = null;
        using (var stream = File.OpenRead("C:\\temp.dat"))
        {
            readFromFile = Serializer.Deserialize(stream);
        }
    
    }
    

提交回复
热议问题