将对象保存到没有序列化属性的文件的最简单方法是什么?

时间:2021-07-13 22:59:10

I have different kinds of objects in c# that I would like to save to a file (XML is preferred) but I can't use serialization since the class are not written by me but are from a DLL.

我在c#中有不同类型的对象,我想保存到文件(XML是首选)但我不能使用序列化,因为该类不是由我编写的,而是来自DLL。

What is the best solution for this ?

什么是最好的解决方案?

5 个解决方案

#1


3  

I eventually used JavaScriptSerializer and it does exactly what I was looking for:

我最终使用了JavaScriptSerializer,它完全符合我的要求:

List<Person> persons = new List<Person>();
persons.Add(new Person(){Name = "aaa"});
persons.Add(new Person() { Name = "bbb" });

JavaScriptSerializer javaScriptSerializer  = new JavaScriptSerializer();
var strData = javaScriptSerializer.Serialize(persons);

var persons2 = javaScriptSerializer.Deserialize<List<Person>>(strData);

#2


1  

I've whipped up a quick little extension method that will "serialize" to XML, given a non-serializable object. It's pretty rough and doesn't do a heck of a lot of checking and the XML it generates you can easily tweak to meet your needs:

鉴于一个不可序列化的对象,我已经掀起了一个快速的小扩展方法,它将“序列化”为XML。它非常粗糙,并且不会进行大量检查,它生成的XML可以轻松调整以满足您的需求:

public static string SerializeObject<T>(this T source, bool serializeNonPublic = false)
{
    if (source == null)
    {
        return null;
    }

    var bindingFlags = BindingFlags.Instance | BindingFlags.Public;

    if (serializeNonPublic)
    {
        bindingFlags |= BindingFlags.NonPublic;
    }

    var properties = typeof(T).GetProperties(bindingFlags).Where(property => property.CanRead).ToList();
    var sb = new StringBuilder();

    using (var writer = XmlWriter.Create(sb))
    {
        writer.WriteStartElement(typeof(T).Name);
        if (properties.Any())
        {
            foreach (var property in properties)
            {
                var value = property.GetValue(source, null);

                writer.WriteStartElement(property.Name);
                writer.WriteAttributeString("Type", property.PropertyType.Name);
                writer.WriteAttributeString("Value", value.ToString());
                writer.WriteEndElement();
            }
        }
        else if (typeof(T).IsValueType)
        {
            writer.WriteValue(source.ToString());
        }

        writer.WriteEndElement();
    }

    return sb.ToString();
}

I tested it on this class:

我在这堂课上测试了它:

private sealed class Test
{
    private readonly string name;

    private readonly int age;

    public Test(string name, int age)
    {
        this.name = name;
        this.age = age;
    }

    public string Name
    {
        get
        {
            return this.name;
        }
    }

    public int Age
    {
        get
        {
            return this.age;
        }
    }
}

as well as the number 3 and object. The resulting XML is as such:

以及数字3和对象。生成的XML如下:

<?xml version="1.0" encoding="utf-16"?>
<Test>
  <Name Type="String" Value="John Doe" />
  <Age Type="Int32" Value="35" />
</Test>

<?xml version="1.0" encoding="utf-16"?>
<Int32>3</Int32>

<?xml version="1.0" encoding="utf-16"?>
<Object />

respectively.

分别。

#3


0  

write your own serializable wrappers around the non-serializable classes of the DLL.

围绕DLL的非可序列化类编写自己的可序列化包装器。

EDIT: AutoMapper was suggested in the comments and I hadn't heard of it yet, but now that I have I'd definitely use that instead of writing the wrappers myself. Unless there's some reflection required to capture some of the internal state of the non-serializable object (if possible), I don't know if AutoMapper has anything to offer there or you'd have to see if you could capture that in your wrapper.

编辑:在评论中建议使用AutoMapper,我还没有听说过,但现在我已经肯定会使用它而不是自己编写包装器。除非需要一些反射来捕获非序列化对象的一些内部状态(如果可能),我不知道AutoMapper是否有任何东西可以提供,或者你必须看看你是否可以在你的包装器中捕获它。

#4


0  

I would write a POCO (Plain Old Class Object) class that mimics the object from the DLL returned. Generally if you are using, I believe, .NET 3.5 or higher you have the ability to use LINQ. I favor Linq to put objects into other classes or perform sorting or other operations on them.

我会编写一个POCO(Plain Old Class Object)类,它模仿返回的DLL中的对象。通常,如果您使用,我相信,.NET 3.5或更高版本,您可以使用LINQ。我赞成Linq将对象放入其他类或对它们执行排序或其他操作。

Here is a simple example where you would be dummying in your return object for example. Keep in mind in a DLL of course you could have many differing objects and do this multiple times. I also would wrap my methods up in their own class for re usability instead of doing it in the main. But here is a simple proof of concept

这是一个简单的例子,例如你将在你的返回对象中愚弄。请记住,在DLL中,您可以拥有许多不同的对象并多次执行此操作。我也会将我的方法包装在他们自己的类中以获得可用性而不是在主要方面。但这是一个简单的概念证明

using System;
using System.Linq;
using System.Windows.Forms;
using System.IO;
using System.Xml.Serialization;
using System.Collections.Generic;
using System.Xml.Linq;

namespace ExampleSerializer
{
    class Program
    {
        // example class to serialize
        [Serializable]
        public class SQLBit
        {
            [XmlElement("Name")]
            public string Name { get; set; }

            [XmlText]
            public string data { get; set; }
        }

        // example class to populate to get test data
        public class example
        {
            public string Name { get; set; }
            public string data { get; set; }
        }

        static void Main(string[] args)
        {
            string s = "";

            // make a generic and put some data in it from the test
            var ls = new List<example> { new example { Name = "thing", data = "data" }, new example { Name = "thing2", data = "data2" } };

            // make a second generic and put data from the first one in using a lambda
            // statement creation method.  If your object returned from DLL is a of a
            // type that implements IEnumerable it should be able to be used.
            var otherlist = ls.Select(n => new SQLBit
                {
                    Name = n.Name,
                    data = n.data
                });

            // start a new xml serialization with a type.
            XmlSerializer xmler = new XmlSerializer(typeof(List<SQLBit>));

            // I use a textwriter to start a new instance of a stream writer
            TextWriter twrtr = new StreamWriter(@"C:\Test\Filename.xml");

            // Serialize the stream to the location with the list
            xmler.Serialize(twrtr, otherlist);

            // Close
            twrtr.Close();

            // TODO: You may want to put this in a try catch wrapper and make up your 
            // own classes.  This is a simple example.
         }
    }
}

#5


0  

I think the term "without-serialization" in the question header is misleading.

我认为问题标题中的“无序列化”一词具有误导性。

If i understood you correctly you want to serialize objects that have no serilisation-attributes.

如果我理解正确你想要序列化没有serilisation属性的对象。

There are libraries like sharpserializer and protobuf-net that can do the job for you.

有像sharpserializer和protobuf-net这样的库可以为你完成这项工作。

#1


3  

I eventually used JavaScriptSerializer and it does exactly what I was looking for:

我最终使用了JavaScriptSerializer,它完全符合我的要求:

List<Person> persons = new List<Person>();
persons.Add(new Person(){Name = "aaa"});
persons.Add(new Person() { Name = "bbb" });

JavaScriptSerializer javaScriptSerializer  = new JavaScriptSerializer();
var strData = javaScriptSerializer.Serialize(persons);

var persons2 = javaScriptSerializer.Deserialize<List<Person>>(strData);

#2


1  

I've whipped up a quick little extension method that will "serialize" to XML, given a non-serializable object. It's pretty rough and doesn't do a heck of a lot of checking and the XML it generates you can easily tweak to meet your needs:

鉴于一个不可序列化的对象,我已经掀起了一个快速的小扩展方法,它将“序列化”为XML。它非常粗糙,并且不会进行大量检查,它生成的XML可以轻松调整以满足您的需求:

public static string SerializeObject<T>(this T source, bool serializeNonPublic = false)
{
    if (source == null)
    {
        return null;
    }

    var bindingFlags = BindingFlags.Instance | BindingFlags.Public;

    if (serializeNonPublic)
    {
        bindingFlags |= BindingFlags.NonPublic;
    }

    var properties = typeof(T).GetProperties(bindingFlags).Where(property => property.CanRead).ToList();
    var sb = new StringBuilder();

    using (var writer = XmlWriter.Create(sb))
    {
        writer.WriteStartElement(typeof(T).Name);
        if (properties.Any())
        {
            foreach (var property in properties)
            {
                var value = property.GetValue(source, null);

                writer.WriteStartElement(property.Name);
                writer.WriteAttributeString("Type", property.PropertyType.Name);
                writer.WriteAttributeString("Value", value.ToString());
                writer.WriteEndElement();
            }
        }
        else if (typeof(T).IsValueType)
        {
            writer.WriteValue(source.ToString());
        }

        writer.WriteEndElement();
    }

    return sb.ToString();
}

I tested it on this class:

我在这堂课上测试了它:

private sealed class Test
{
    private readonly string name;

    private readonly int age;

    public Test(string name, int age)
    {
        this.name = name;
        this.age = age;
    }

    public string Name
    {
        get
        {
            return this.name;
        }
    }

    public int Age
    {
        get
        {
            return this.age;
        }
    }
}

as well as the number 3 and object. The resulting XML is as such:

以及数字3和对象。生成的XML如下:

<?xml version="1.0" encoding="utf-16"?>
<Test>
  <Name Type="String" Value="John Doe" />
  <Age Type="Int32" Value="35" />
</Test>

<?xml version="1.0" encoding="utf-16"?>
<Int32>3</Int32>

<?xml version="1.0" encoding="utf-16"?>
<Object />

respectively.

分别。

#3


0  

write your own serializable wrappers around the non-serializable classes of the DLL.

围绕DLL的非可序列化类编写自己的可序列化包装器。

EDIT: AutoMapper was suggested in the comments and I hadn't heard of it yet, but now that I have I'd definitely use that instead of writing the wrappers myself. Unless there's some reflection required to capture some of the internal state of the non-serializable object (if possible), I don't know if AutoMapper has anything to offer there or you'd have to see if you could capture that in your wrapper.

编辑:在评论中建议使用AutoMapper,我还没有听说过,但现在我已经肯定会使用它而不是自己编写包装器。除非需要一些反射来捕获非序列化对象的一些内部状态(如果可能),我不知道AutoMapper是否有任何东西可以提供,或者你必须看看你是否可以在你的包装器中捕获它。

#4


0  

I would write a POCO (Plain Old Class Object) class that mimics the object from the DLL returned. Generally if you are using, I believe, .NET 3.5 or higher you have the ability to use LINQ. I favor Linq to put objects into other classes or perform sorting or other operations on them.

我会编写一个POCO(Plain Old Class Object)类,它模仿返回的DLL中的对象。通常,如果您使用,我相信,.NET 3.5或更高版本,您可以使用LINQ。我赞成Linq将对象放入其他类或对它们执行排序或其他操作。

Here is a simple example where you would be dummying in your return object for example. Keep in mind in a DLL of course you could have many differing objects and do this multiple times. I also would wrap my methods up in their own class for re usability instead of doing it in the main. But here is a simple proof of concept

这是一个简单的例子,例如你将在你的返回对象中愚弄。请记住,在DLL中,您可以拥有许多不同的对象并多次执行此操作。我也会将我的方法包装在他们自己的类中以获得可用性而不是在主要方面。但这是一个简单的概念证明

using System;
using System.Linq;
using System.Windows.Forms;
using System.IO;
using System.Xml.Serialization;
using System.Collections.Generic;
using System.Xml.Linq;

namespace ExampleSerializer
{
    class Program
    {
        // example class to serialize
        [Serializable]
        public class SQLBit
        {
            [XmlElement("Name")]
            public string Name { get; set; }

            [XmlText]
            public string data { get; set; }
        }

        // example class to populate to get test data
        public class example
        {
            public string Name { get; set; }
            public string data { get; set; }
        }

        static void Main(string[] args)
        {
            string s = "";

            // make a generic and put some data in it from the test
            var ls = new List<example> { new example { Name = "thing", data = "data" }, new example { Name = "thing2", data = "data2" } };

            // make a second generic and put data from the first one in using a lambda
            // statement creation method.  If your object returned from DLL is a of a
            // type that implements IEnumerable it should be able to be used.
            var otherlist = ls.Select(n => new SQLBit
                {
                    Name = n.Name,
                    data = n.data
                });

            // start a new xml serialization with a type.
            XmlSerializer xmler = new XmlSerializer(typeof(List<SQLBit>));

            // I use a textwriter to start a new instance of a stream writer
            TextWriter twrtr = new StreamWriter(@"C:\Test\Filename.xml");

            // Serialize the stream to the location with the list
            xmler.Serialize(twrtr, otherlist);

            // Close
            twrtr.Close();

            // TODO: You may want to put this in a try catch wrapper and make up your 
            // own classes.  This is a simple example.
         }
    }
}

#5


0  

I think the term "without-serialization" in the question header is misleading.

我认为问题标题中的“无序列化”一词具有误导性。

If i understood you correctly you want to serialize objects that have no serilisation-attributes.

如果我理解正确你想要序列化没有serilisation属性的对象。

There are libraries like sharpserializer and protobuf-net that can do the job for you.

有像sharpserializer和protobuf-net这样的库可以为你完成这项工作。