首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >反序列化器的简单通用输出

反序列化器的简单通用输出
EN

Code Review用户
提问于 2015-01-21 06:08:01
回答 3查看 4.8K关注 0票数 11

最近,我一直在学习序列化,所以我决定为我的应用程序编写一个小助手类,以便于在多个地方使用这个特性。实际上,我在代码中混合了一些泛型,并希望听到您对我的总体方法的反馈。

SerializationService.cs

代码语言:javascript
复制
public class SerializationService
{
    /// <summary>
    /// This method Serializes the given Obj into an XML file.
    /// </summary>
    /// <param name="myObject">The obj to be serialized.</param>
    /// <param name="fileFullPath">The file name with the full
    /// path for the output serialized XML file.</param>
    public static void SerializeToFile(Object myObject, string fileFullPath)
    {
        var xmlDoc = new XmlDocument();
        var xmlSerializer = new XmlSerializer(myObject.GetType());
        using (var fs = new FileStream(fileFullPath, FileMode.Create))
        {
            var writer = new XmlTextWriter(fs, Encoding.Unicode);
            xmlSerializer.Serialize(writer, myObject);
            writer.Close();
        }
    }

    /// <summary>
    /// This method deserializes the XML file into an Obj.
    /// </summary>
    /// <param name="fuleFullPath">The XML file to read.</param>
    /// <returns>Deserialized obj of a type T.</returns>
    public static T DeserializeToObj<T>(string fuleFullPath)
    {
        var xmlSerializer = new XmlSerializer(typeof(T));
        using (var reader = new FileStream(fuleFullPath, FileMode.Open))
        {
            return (T) xmlSerializer.Deserialize(reader);
        }
    }
}

下面是我如何在代码中使用它:

序列化

代码语言:javascript
复制
SerializationService.SerializeToFile(
    _partRepository.GetParts().Where(p => p.IsIgnored).ToList(),
    fileFullPath);

De-serialization

代码语言:javascript
复制
var ignoredParts = SerializationService.DeserializeToObj<List<Part>>(ignoredPartsXml);
EN

回答 3

Code Review用户

回答已采纳

发布于 2015-01-21 10:35:00

这里有几点评论。我不是完美的,也不是编写完美的代码,但我希望这些技巧将有助于编写更好的代码:

命名一致性:

如果您的两个方法的名称有相反的名称,则更容易理解。例如:SerializeToFileDeserializeFromFile。很明显,反序列化将返回一个对象,忽略名称中的对象。

另外,如果在一个方法中使用相同类型/类型的参数或变量,则在另一个方法中给它取相同的名称。

真正通用:

您也应该使序列化方法成为通用方法:

代码语言:javascript
复制
public static void SerializeToFile<T>(T obj, string fullPath)

在point Type约束中,您将进一步了解其中的原因。

作用域变量:

您应该尽可能地定义变量的用法。在您的示例中,您可以在XmlSerializer语句中实例化using类,因为在语句之外不需要它。示例:

代码语言:javascript
复制
using (var stream = new FileStream(fullPath, FileMode.Open))
{
    var xmlSerializer = new XmlSerializer(typeof(T));
}

检查文件:

在这两种方法中,都可以在某些情况下引发异常。在序列化方法中,如果路径不存在,您将得到一个DirectoryNotFoundException;在反序列化方法中,如果文件不存在,您将得到一个FileNotFoundException。这一问题很容易解决:

代码语言:javascript
复制
//Check for directory in serialize:
var directoryPath = Path.GetDirectory(fileFullPath);
var directoryExists = Directory.Exists(directoryPath);

//Check for file in deserialize
var fileExists = File.Exists(fileFullPath);

你应该决定你想要正面的还是负面的评价。例如,只有在检查为正时才执行该方法,如果检查为否定,则抛出参数异常。那就看你的了。

另外,就像赫斯拉赫所说的:如果文件已经存在了怎么办?目前,该文件的内容将被新内容覆盖。

using语句:

以下是:

代码语言:javascript
复制
using (var fs = new FileStream(fileFullPath, FileMode.Create))
{
    var writer = new XmlTextWriter(fs, Encoding.Unicode);
    xmlSerializer.Serialize(writer, myObject);
    writer.Close();
}

可代之以:

代码语言:javascript
复制
using (var stream = new FileStream(fullPath, FileMode.Create))
using (var writer = new XmlTextWriter(stream, Encoding.Unicode))
{
    var xmlSerializer = new XmlSerializer(obj.GetType());
    xmlSerializer.Serialize(writer, obj);
}

类型约束:

还记得我让序列化方法也是通用的吗?现在,您不验证传入和传出对象。如果我传递一个没有公共无参数构造函数的类的实例,该怎么办?在运行时,我将得到一个InvalidOperationException,其消息如下:

..。无法序列化,因为它没有无参数的构造函数。

解决方案是在方法上放置类型约束。来自MSDN的定义:

定义泛型类时,可以将限制应用于客户端代码在实例化类时可用于类型参数的类型,这些限制称为约束。

您应该使用classnew()类型约束。他们的定义如下:

  • 类:类型参数必须是引用类型;这也适用于任何类、接口、委托或数组类型。
  • new():type参数必须有一个公共的无参数构造函数。当与其他约束一起使用时,必须最后指定新()约束。

现在,当您尝试序列化没有公共无参数构造函数的clas实例时,您将得到一个编译时异常。您可以在这里阅读更多内容:关于类型参数的约束(C#编程指南)

代码语言:javascript
复制
public static void SerializeToFile<T>(T obj, string fullPath) where T : class, new()
{
    //method body
}

public static T DeserializeFromFile<T>(string fullPath) where T : class, new()
{
    //method body
}

最终代码:

所有这些应用之后,您的代码可能如下所示:

代码语言:javascript
复制
public class SerializationService
{
    public static void SerializeToFile<T>(T obj, string fullPath) where T : class, new()
    {
        if(Directory.Exists(Path.GetDirectoryName(fullPath)))
        {
            using (var stream = new FileStream(fullPath, FileMode.Create))
            using (var writer = new XmlTextWriter(stream, Encoding.Unicode))
            {
                var xmlSerializer = new XmlSerializer(obj.GetType());
                xmlSerializer.Serialize(writer, obj);
            }
        }
    }

    public static T DeserializeFromFile<T>(string fullPath) where T : class, new()
    {
        if(File.Exists(fullPath))
        {
            using (var stream = new FileStream(fullPath, FileMode.Open))
            {
                var xmlSerializer = new XmlSerializer(typeof(T));
                return (T) xmlSerializer.Deserialize(stream);
            }
        }
        return default(T);
    }
}
票数 11
EN

Code Review用户

发布于 2015-01-21 06:39:12

  • string fuleFullPath将是一个错误。
  • 如果文件存在,您应该在DeserializeToObj上检查。如果没有,你应该抛出一个异常。
  • 如果文件已经存在,您应该考虑一下SerializeToFile的策略。
  • var xmlDoc = new XmlDocument();没有做任何事情,应该删除。
  • 您应该考虑将DeserializeToObj()方法重命名为Deserialize()。很明显,它反序列化为一个对象。
  • 你应该和命名一致。在SerializeToFile()方法中,将FileStream对象fs命名为DeserializeToObj()方法,称为reader
票数 7
EN

Code Review用户

发布于 2015-01-21 08:55:59

  1. SerializeToFile也应该是通用的。序列化方法在Object上工作似乎很奇怪,而反序列化方法是泛型的。
  2. 我会考虑添加从/序列化到流的方法。虽然您已经有效地应用了YAGNI,但是一旦项目超出了基本实验的范围,我经常会遇到对流的写入/读取。
票数 5
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/78191

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档