samedi 13 août 2016

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

I am writing a toy language with Antlr4 and C#. Now i am trying to write a class system. But a big problem stopped my all work. When i try to clone instance of a user created class , everything in it references to original class. My 'Class' code is here

[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;
    }
}

and code for '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;
    }
}

and a superclass code

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()
    { }
}

I writed VarCollection, FunctionCollection and ClassCollection myself They are just lists with find and exists methods. When i try a code like this in my language

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

both 'new1a' and new2a is set to 10. I tried most of techniques including: Reflection, Serialization, JsonSerialization, ICloneable, MemberWiseClone...

In serialization, I need to put [Serializable] to every class, including Antlr4 auto generated classes. So when I update grammar I need to put them again.

In Json Serialization(NewtonJson), serialization enters a infinite loop (Serializator warned me about self referencing loop and i disabled loop error).

Reflection, IClonable, MemberWiseClone, none of these worked correctly. They reference same address at memory so i get same error.

Any help?





Aucun commentaire:

Enregistrer un commentaire