Action<IInternalObjectDBTransaction, DBObjectMetadata, AbstractBufferedReader, object> CreateLoader(uint version)
{
EnsureClientTypeVersion();
var method = ILBuilder.Instance.NewMethod<Action<IInternalObjectDBTransaction, DBObjectMetadata, AbstractBufferedReader, object>>(
$"Loader_{Name}_{version}");
var ilGenerator = method.Generator;
ilGenerator.DeclareLocal(ClientType);
ilGenerator
.Ldarg(3)
.Castclass(ClientType)
.Stloc(0);
var tableVersionInfo = _tableVersions.GetOrAdd(version, version1 => _tableInfoResolver.LoadTableVersionInfo(_id, version1, Name));
var clientTableVersionInfo = ClientTableVersionInfo;
var anyNeedsCtx = tableVersionInfo.NeedsCtx() || clientTableVersionInfo.NeedsCtx();
if (anyNeedsCtx)
{
ilGenerator.DeclareLocal(typeof(IReaderCtx));
ilGenerator
.Ldarg(0)
.Ldarg(2)
.Newobj(() => new DBReaderCtx(null, null))
.Stloc(1);
}
var props = _clientType.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
for (int fi = 0; fi < tableVersionInfo.FieldCount; fi++)
{
var srcFieldInfo = tableVersionInfo[fi];
Action<IILGen> readerOrCtx;
if (srcFieldInfo.Handler.NeedsCtx())
readerOrCtx = il => il.Ldloc(1);
else
readerOrCtx = il => il.Ldarg(2);
var destFieldInfo = clientTableVersionInfo[srcFieldInfo.Name];
if (destFieldInfo != null)
{
var fieldInfo = props.First(p => GetPersistantName(p) == destFieldInfo.Name).GetSetMethod(true);
var fieldType = fieldInfo.GetParameters()[0].ParameterType;
var specializedSrcHandler = srcFieldInfo.Handler.SpecializeLoadForType(fieldType, destFieldInfo.Handler);
var willLoad = specializedSrcHandler.HandledType();
var converterGenerator = _tableInfoResolver.TypeConvertorGenerator.GenerateConversion(willLoad, fieldType);
if (converterGenerator != null)
{
ilGenerator.Ldloc(0);
specializedSrcHandler.Load(ilGenerator, readerOrCtx);
converterGenerator(ilGenerator);
ilGenerator.Call(fieldInfo);
continue;
}
}
srcFieldInfo.Handler.Skip(ilGenerator, readerOrCtx);
}
if (ClientTypeVersion != version)
{
for (int fi = 0; fi < clientTableVersionInfo.FieldCount; fi++)
{
var srcFieldInfo = clientTableVersionInfo[fi];
var iFieldHandlerWithInit = srcFieldInfo.Handler as IFieldHandlerWithInit;
if (iFieldHandlerWithInit == null) continue;
if (tableVersionInfo[srcFieldInfo.Name] != null) continue;
Action<IILGen> readerOrCtx;
if (srcFieldInfo.Handler.NeedsCtx())
readerOrCtx = il => il.Ldloc(1);
else
readerOrCtx = il => il.Ldnull();
var specializedSrcHandler = srcFieldInfo.Handler;
var willLoad = specializedSrcHandler.HandledType();
var setterMethod = props.First(p => GetPersistantName(p) == srcFieldInfo.Name).GetSetMethod(true);
var converterGenerator = _tableInfoResolver.TypeConvertorGenerator.GenerateConversion(willLoad, setterMethod.GetParameters()[0].ParameterType);
if (converterGenerator == null) continue;
if (!iFieldHandlerWithInit.NeedInit()) continue;
ilGenerator.Ldloc(0);
iFieldHandlerWithInit.Init(ilGenerator, readerOrCtx);
converterGenerator(ilGenerator);
ilGenerator.Call(setterMethod);
}
}
ilGenerator.Ret();
return method.Create();
}