在 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 秒)。这是我解决问题的方法。有谁知道解析器生成器或创建语言的好教程,这是我标记此答案之前的最后一个问题。
我正在用 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 秒)。这是我解决问题的方法。有谁知道解析器生成器或创建语言的好教程,这是我标记此答案之前的最后一个问题。