public static void GenUpdateFrom(Type type, bool pooled, string funcPrefix = "") { const string instanceCastedName = "otherConcrete"; const string instanceName = "other"; string otherName = instanceName; var flag = pooled ? GenTaskFlags.PooledUpdateFrom : GenTaskFlags.UpdateFrom; var updateFromType = type.TopParentImplementingFlag(flag) ?? type; MethodBuilder sink = MakeGenMethod(type, flag, funcPrefix + UpdateFuncName, typeof(void), $"{updateFromType.RealName(true)} {instanceName}{(pooled ? ", ObjectPool pool" : "")}"); if (type.IsList()) { // For livable list that we do not need to generate in not constructed form if (type.IsConstructedGenericType == false) { return; } var elemType = type.GenericTypeArguments[0]; SinkUpdateFromList(sink, elemType, type.AccessPrefixInGeneratedFunction(), otherName, pooled, updateWhenAssigned: type.IsDataList()); } else if (type.IsArray) { var elemType = type.GetElementType(); SinkArrayUpdateFromWithFixedSize(sink, elemType, type.AccessPrefixInGeneratedFunction(), otherName, pooled); } else if (type.IsDictionary()) { Error($"Update from for dictionary ({type}) is not supported"); } else { if (type != updateFromType) { otherName = instanceCastedName; sink.content($"var {instanceCastedName} = ({type.RealName(true)}){instanceName};"); var directUpdateSink = GenClassSink(type).Method(funcPrefix + UpdateFuncName, type, MethodType.Instance, typeof(void), $"{type.RealName(true)} {instanceName}{(pooled ? ", ObjectPool pool" : "")}"); directUpdateSink.content($"this.UpdateFrom(({updateFromType.RealName(true)})other{(pooled ? ", pool" : "")});"); directUpdateSink.classBuilder.inheritance($"I{(pooled ? "Pooled" : "")}UpdatableFrom<{type.RealName(true)}>"); } if (type.IsControllable()) { GenClassSink(type) .inheritance($"I{(pooled ? "Pooled" : "")}UpdatableFrom<{updateFromType.RealName(true)}>"); } type.ProcessMembers(flag, true, memberInfo => { GenUpdateValueFromInstance(sink, memberInfo, memberInfo.valueTransformer($"{otherName}.{memberInfo.baseAccess}"), pooled); }); } }
public static void GeneralReadFrom(MethodBuilder sink, DataInfo info, Action <MethodBuilder, DataInfo> baseReadCall, string isNullReader, string classIdReader, string directReader, string refInst, string refIdReader, bool pooled, Func <Type, string> configIdReader = null, bool needCreateVar = false, bool useTempVarThenAssign = false, bool getDataNodeFromRootWithRefId = false) { var t = info.type; var canBeNull = info.canBeNull && !t.IsValueType; var originalInfo = info; string tempVar = "__" + originalInfo.baseAccess.Replace("[", "").Replace("]", ""); if (useTempVarThenAssign) { sink.content($"var {tempVar} = {originalInfo.access};"); info = new DataInfo { type = originalInfo.type, baseAccess = tempVar, }; } var name = info.access; bool newInstCalled = false; if (needCreateVar) { sink.content($"{info.type.RealName(true)} {info.name} = default;"); } if (t.IsImmutableValueType() || t.IsValueType && t.IsControllable() == false) { sink.content($"{name} = {directReader};"); return; } else if (t.IsRef()) { if (CodeGenTools.Valid(refIdReader)) { sink.content($"{info.access}.id = {refIdReader};"); } else { throw new NotImplementedException(); } } else { if (canBeNull) { sink.content($"if ({isNullReader}) {{"); sink.indent++; SinkRemovePostProcess(sink, info, pooled); sink.content($"{name} = null;"); sink.indent--; sink.content($"}}"); sink.content($"else {{ "); sink.indent++; } bool fromExternalSource = false; if (t.IsConfig() && info.insideConfigStorage == false) { ConfigFromId(sink, info, configIdReader, false); fromExternalSource = true; } else if (getDataNodeFromRootWithRefId && typeof(IReferencableFromDataRoot).IsAssignableFrom(t)) { sink.content($"{info.access} = ({info.type.RealName(true)})root.Recall({refIdReader});"); fromExternalSource = true; } else { if (info.sureIsNull && !info.type.IsValueType) { CreateNewInstance(sink, info, classIdReader, pooled, refInst, false); newInstCalled = true; } else { string createNewCondition = ""; if (canBeNull || info.CanBeNullAfterConstruction()) { createNewCondition = $"{name} == null"; } string classIdVarName = $"{name.Replace('[', '_').Replace(']', '_').Replace('.', '_')}ClassId"; if (t.CanBeAncestor() && info.cantBeAncestor == false) { sink.content($"var {classIdVarName} = {classIdReader};"); createNewCondition = AddOrCondition(createNewCondition, $"{name}.{PolymorphClassIdGetter} != {classIdVarName}"); } if (info.type.IsImmutableType() == false && CodeGenTools.Valid(createNewCondition)) { sink.content($"if ({createNewCondition}) {{"); sink.indent++; SinkRemovePostProcess(sink, info, pooled); CreateNewInstance(sink, info, classIdVarName, pooled, refInst, false); newInstCalled = true; sink.indent--; sink.content($"}}"); } } } if (!fromExternalSource) { baseReadCall(sink, info); } if (canBeNull) { sink.indent--; sink.content($"}}"); } } if (useTempVarThenAssign) { sink.content($"{originalInfo.access} = {tempVar};"); } }