在 C# 中深度克隆深层对象(非常深)

Deep cloning a deep object in C# (very deep)

我正在用 Antlr4 和 C# 编写一种玩具语言。现在我正在尝试编写一个 class 系统。但是一个大问题阻止了我所有的工作。当我尝试克隆用户创建的实例 class 时,其中的所有内容都引用原始 class。我的 'Class' 代码在这里

[Serializable]
public class Class : ICloneable
{
    public string ID;
    public ClassDef ClassContent = new ClassDef();

    public Helper ErrorHandler = new Helper();

    public Class()
    {
        ID = "";
    }
    public Class(string id)
    {
        ID = id;
    }

    public void Create(MainGrammarParser.ClassblockContext block)
    {
        ClassDef def = new ClassDef();
        def.Visit(block);
        ClassContent = def;
    }

    public object Clone()
    {
        Class clone = new Class(ID);
        clone.ClassContent = ClassContent.DeepClone();
        return clone;
    }
}

和 'ClassDef'

的代码
public class ClassDef : SuperClass, ICloneable
{
    public override bool VisitClassStatFunctionDef([NotNull] MainGrammarParser.ClassStatFunctionDefContext context)
    {
        FunctionDefParser fd = GetFunctionDefParser();
        fd.Visit(context.functiondef());
        return true;
    }

    public override bool VisitClassStatElementDef([NotNull] MainGrammarParser.ClassStatElementDefContext context)
    {
        string id = context.classelem().ID().GetText();
        if (IsVarExists(id) || IsFunctionExists(id) || IsClassExists(id))
        {
            ErrorHandler.DuplicateError("[ELEMENT] '" + id  + "'");
        }
        ExpParser exp = GetExpParser();
        VarObject v = new VarObject(id);
        v.Value = exp.Visit(context.classelem().exp());
        Variables.Add(v);
        return true;
    }
}

还有一个超级class码

public class SuperClass : MainGrammarBaseVisitor<bool>, ICloneable
{
    public VarCollection Variables = new VarCollection();
    public FunctionCollection Functions = new FunctionCollection();
    public ClassCollection Classes = new ClassCollection();

    public Helper ErrorHandler = new Helper();

    public VarObject GetVar(string id)
    {
        if (!IsVarExists(id))
        {
            ErrorHandler.NotFoundError("[DEFINITION] '" + id + "'");
        }
        return Variables.Find(id);
    }

    public Function GetFunction(string id)
    {
        if (!IsFunctionExists(id))
        {
            ErrorHandler.NotFoundError("[METHOD] '" + id + "'");
        }
        return Functions.Find(id);
    }

    public Class GetClass(string id)
    {
        if (!IsClassExists(id))
        {
            ErrorHandler.NotFoundError("[CLASS] '" + id + "'");
        }
        return Classes.Find(id);
    }

    public bool IsVarExists(string id)
    {
        if (!Variables.Contains(id)) { return false; }
        return true;
    }

    public bool IsFunctionExists(string id)
    {
        if (!Functions.Contains(id)) { return false; }
        return true;
    }

    public bool IsClassExists(string id)
    {
        if (!Classes.Contains(id)) { return false; }
        return true;
    }

    public ExpParser GetExpParser()
    {
        ExpParser output = new ExpParser();
        output.Parent = this;
        return output;
    }

    public EqualityParser GetEqualityParser()
    {
        EqualityParser output = new EqualityParser();
        output.Parent = this;
        return output;
    }

    public FunctionDefParser GetFunctionDefParser()
    {
        FunctionDefParser output = new FunctionDefParser();
        output.Parent = this;
        return output;
    }

    public IfParser GetIfParser()
    {
        IfParser output = new IfParser();
        output.Parent = this;
        return output;
    }

    public object Clone()
    {
        SuperClass output = new SuperClass();
        output.Variables = Variables.DeepClone();
        output.Functions = Functions.DeepClone();
        output.Classes = Classes.DeepClone();
        return output;
    }

    public SuperClass()
    { }
}

我自己写了VarCollection、FunctionCollection和ClassCollection 它们只是带有 find 和 exists 方法的列表。 当我用我的语言尝试这样的代码时

class abc
{
    this a = "a"
    this b = "b"
    this c = "c"
    void abc(){}
}
newabc1 = new abc()
newabc1.a = 10
new1a = newabc1.a
newabc2 = new abc()
new2a = newabc2.a

'new1a' 和 new2a 都设置为 10。 我尝试了大部分技术,包括:反射、序列化、Json序列化、ICloneable、MemberWiseClone...

在序列化中,我需要将 [Serializable] 放入每个 class,包括 Antlr4 自动生成的 classes。所以当我更新语法时,我需要重新放置它们。

在Json序列化(NewtonJson)中,序列化进入无限循环(Serializator警告我关于自引用循环,我禁用了循环错误)。

Reflection、IClonable、MemberWiseClone,其中 none 工作正常。他们在内存中引用了相同的地址,所以我得到了同样的错误。

有什么帮助吗?

您可以使用序列化来深度克隆对象,但请记住您必须设置:

ReferenceLoopHandling = ReferenceLoopHandling.Ignore

到你的序列化器,以防止进入无限循环。这是如果您正在使用 Newtonsoft but similar ReferenceLoopHandling setting 许多序列化程序都存在选项。

我解决了问题,但不是真的 :) 我使用字典实例作为 类(如 JavaScript)。当您将它与 Antlr 一起使用时,在 NewtonJson 中创建序列化对象是低效的,因为巨大的源代码使得序列化非常缓慢(大约 2-3 秒)。这是我解决问题的方法。有谁知道解析器生成器或创建语言的好教程,这是我标记此答案之前的最后一个问题。