public MapStrategy(IRecord record) { if (record.ContainsOnlyPrimitives()) { var loader = DictionaryLoad.DirectlyFromRecord(); _mapMethod = BuildMappingMethod( from p in typeof(TReturn).GetProperties(ObjectToDictionary.BindingFlagsForDTO) let neoName = Config.DotnetToNeoPropNames(p.Name) where p.CanWrite select new PropertyMap { Loader = loader, Property = p, RecordKey = neoName }); } else if (record.ContainsOnlySingleNode()) { var nodeKey = record.Keys.First(); var loader = DictionaryLoad.FromEmbeddedNode(nodeKey); _mapMethod = BuildMappingMethod( from p in typeof(TReturn).GetProperties(ObjectToDictionary.BindingFlagsForDTO) let neoName = Config.DotnetToNeoPropNames(p.Name) where p.CanWrite select new PropertyMap { Loader = loader, Property = p, RecordKey = neoName }); } }
private Func <IRecord, TReturn> BuildMappingMethod(IEnumerable <PropertyMap> propertyMaps) { var emit = Emit <Func <IRecord, TReturn> > .NewDynamicMethod($"MapTo_{typeof(TReturn).Name}_{Guid.NewGuid().ToBase64Guid()}"); var ret = emit.DeclareLocal(typeof(TReturn)); var v = emit.DeclareLocal(typeof(object)); var check = emit.DeclareLocal(typeof(bool)); var valueDict = emit.DeclareLocal(typeof(IReadOnlyDictionary <string, object>)); emit.NewObject(typeof(TReturn)); emit.StoreLocal(ret); int labelCounter = 0; DictionaryLoad currentLoader = null; foreach (var pm in propertyMaps) { if (!ReferenceEquals(currentLoader, pm.Loader)) { // valueDict = record.Values || ((INode)record["v"]).Properties || ... currentLoader = pm.Loader; currentLoader.EmitLoad(emit, valueDict); } // check = dict.TryGetValue(recordKey, out v) // if (check) // ret.Property = (cast)v; var lbl = emit.DefineLabel("lbl_" + labelCounter); emit.LoadLocal(valueDict); emit.LoadConstant(pm.RecordKey); emit.LoadLocalAddress(v); emit.CallVirtual(TryGetValue); emit.AsShorthand().Ldc(0); // <-- Copied from looking at IL emit.AsShorthand().Ceq(); // it seems to turn around the true val emit.StoreLocal(check); // and jump to the label emit.LoadLocal(check); emit.BranchIfTrue(lbl); emit.LoadLocal(ret); emit.LoadLocal(v); if (pm.Property.PropertyType.GetTypeInfo().IsValueType) { emit.UnboxAny(pm.Property.PropertyType); } else { emit.CastClass(pm.Property.PropertyType); } emit.CallVirtual(pm.Property.SetMethod); emit.MarkLabel(lbl); labelCounter++; } emit.LoadLocal(ret); emit.Return(); return(emit.CreateDelegate()); }