【问题标题】:Is there a serializer for .net which will output c# code?是否有用于.net 的序列化程序来输出 c# 代码?
【发布时间】:2013-04-09 13:03:50
【问题描述】:

我正在寻找一个可以获取实例的序列化程序,并将其序列化为一个包含 c# 代码的字符串,表示图形的内容。 该类的功能类似于 JSON.NET 中的SerializeObject

我知道只有非常有限的一组结构会起作用,但我感兴趣的结构非常简单,而且它们会起作用。

如果有人知道具有类似功能的 Visual Studio Visualizer,则可以加分。

编辑: 输出将在编译时用于不同的应用程序。我不需要在运行时反序列化输出(c# 代码),它会保存到文件中进行分析。

var foo = new Foo() { Number = 1, Bar = new Bar() { Str = "Bar"}};
string sourceCode = Magic.SerializeObject(foo);

输出:

Foo obj = new Foo();
obj.Number = 1;
obj.RefType = null; // infer this
obj.Bar = new Bar();
obj.Bar.Str = "Bar";

【问题讨论】:

  • stackoverflow.com/questions/6503762/… 你试过 XmlSerializer 了吗?
  • @Androidy 我经常使用它。它只序列化为 XML,而不是 c#。
  • 我不知道一个现成的解决方案,但也许你想看看 Visual Studio 用于代码生成的 T4 文本模板...msdn.microsoft.com/en-us/library/dd820620.aspx...一点有点反思,你很高兴......
  • 从技术上讲,这是 C# 代码 Foo obj = JsonConvert.Deserialize<Foo>("[the json]");,但它显然与您的示例输出不匹配。您介意分享一下为什么需要 C# 代码吗?
  • 等等,伙计们,你们误解了我在寻找什么。我不想在运行时发出代码/创建新类型,或者类似的东西。我想采用一个数据结构,将其序列化为 c# 代码表示。然后我将此输出保存到文件中。我在稍后阶段获取此输出,并将其用于正常编译的不同项目中,以提供“真实”测试数据。我希望它在 c# 中,而不是 JSON/XML/etc 中,因为如果/当我们更改类时,编译器可以确保数据结构匹配。很抱歉有任何混淆。

标签: c# .net serialization


【解决方案1】:

是的,不是……

最接近的解决方案称为CodeDOM,它是大多数 Visual Studio 设计人员和向导用来生成代码的方法。


仔细查看您的 cmets 后,我认为您应该仔细阅读 MSDN 中的 Binary Serialization 部分,它将满足您的所有要求。

您正在寻找的是序列化,您不想每次都重新编译第二个项目,对吧? 你只想要 validation 和向前\向后 compatibility

【讨论】:

  • @jasper,基本上没有,为什么要序列化为源代码,本质上是反编译。以“可往返”的方式相对难以做到,尤其是在一般情况下。您最终会得到更详细的状态表示。您可能会争辩说它更具人类可读性,但 XML 和 JSON 非常适合。 +1
  • @Jodrell 我想你应该把这个放在这个问题上 ;-)
  • +1 位被准确定向。
  • 我的意思是评论,但是好的:-)
  • 实际上,我确实想每次都重新编译,因为我们需要编译时间检查,但看起来你对 CodeDOM 很满意,尤其是 svick 提供的解决方案。感谢您的帮助。
【解决方案2】:

使用 CodeDom 编写这样的东西其实比较简单:

class CSharpSerializer
{
    private readonly Dictionary<string, int> m_locals =
        new Dictionary<string, int>();

    private readonly List<CodeStatement> m_statements =
        new List<CodeStatement>();

    private string GetVariableName(string suggestedName)
    {
        suggestedName = suggestedName.TrimEnd("0123456789".ToCharArray());

        int n;
        if (m_locals.TryGetValue(suggestedName, out n))
        {
            n++;
            m_locals[suggestedName] = n;
            return suggestedName + n;
        }

        m_locals[suggestedName] = 1;
        return suggestedName;
    }

    public string SerializeObject(object obj)
    {
        m_statements.Clear();

        // dynamic used to make the code simpler
        GetExpression((dynamic)obj);

        var compiler = new CSharpCodeProvider();
        var writer = new StringWriter();
        foreach (var statement in m_statements)
        {
            compiler.GenerateCodeFromStatement(
                statement, writer, new CodeGeneratorOptions());
        }
        return writer.ToString();
    }

    private static CodeExpression GetExpression(int i)
    {
        return new CodePrimitiveExpression(i);
    }

    private static CodeExpression GetExpression(string s)
    {
        return new CodePrimitiveExpression(s);
    }

    private static CodeExpression GetExpression(DateTime dateTime)
    {
        // TODO: handle culture and milliseconds
        return new CodeMethodInvokeExpression(
            new CodeTypeReferenceExpression(typeof(Convert)), "ToDateTime",
            new CodePrimitiveExpression(Convert.ToString(dateTime)));
    }

    // and so on for other primitive types
    // and types that require special handling (including arrays)

    private CodeExpression GetExpression(object obj)
    {
        if (obj == null)
            return new CodePrimitiveExpression(null);

        var type = obj.GetType();
        string typeName = type.Name;

        string variable = GetVariableName(
            typeName[0].ToString().ToLower() + typeName.Substring(1));

        m_statements.Add(
            new CodeVariableDeclarationStatement(
                typeName, variable, new CodeObjectCreateExpression(typeName)));

        foreach (var property in type.GetProperties(
            BindingFlags.Public | BindingFlags.Instance))
        {
            var expression = GetExpression((dynamic)property.GetValue(obj));
            m_statements.Add(
                new CodeAssignStatement(
                    new CodePropertyReferenceExpression(
                        new CodeVariableReferenceExpression(variable),
                        property.Name),
                    expression));
        }

        return new CodeVariableReferenceExpression(variable);
    }
}

在很多情况下这段代码会失败,但是对于行为良好的类型(公共默认构造函数,所有公共实例属性都有设置器,字段或非公共属性中没有隐藏重要状态,没有循环引用,没有命名空间冲突等),它将起作用。

【讨论】:

  • 太棒了,非常感谢这个解决方案。为你+1。理想情况下我会奖励你们两个,但 AK_ 提供了第一个 codeDOM 答案,所以除非有人反对,否则我会奖励他?
  • @jasper 这完全取决于你接受哪个答案,所以我认为没有任何反对意见是相关的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-25
相关资源
最近更新 更多