private static void BuildIdAccess(Type entityType, ref MetadataStorage metadataStorage, out Func <object, string> idGetAccessor, out Action <object, string> idSetAccessor) { var idMember = GetIdMember(entityType); if (idMember == null) { var ms = metadataStorage = metadataStorage ?? new MetadataStorage(); string GetIdFromMetadata(object entity) { return(ms.GetMetadata(entity).GetId()); } void SetIdToMetadata(object entity, string id) { ms.GetMetadata(entity).SetId(id); } idGetAccessor = GetIdFromMetadata; idSetAccessor = SetIdToMetadata; return; } // We could theoretically allow setting id to an entity, // but this will need support for transforming a stringified id back to its original representation. idSetAccessor = null; var idType = DataPropertyHelper.GetIdType(entityType); var entityParameter = Expression.Parameter(typeof(object), "entity"); var convertedEntity = Expression.Convert(entityParameter, entityType); var idAccess = default(Expression); if (idMember.MemberType == MemberTypes.Method) { idAccess = Expression.Call(convertedEntity, (MethodInfo)idMember); } else if (idMember.MemberType == MemberTypes.Field || idMember.MemberType == MemberTypes.Property) { idAccess = Expression.MakeMemberAccess(convertedEntity, idMember); } var toStringMethod = idType.GetMethod(nameof(ToString), BindingFlags.Public | BindingFlags.Instance, Type.DefaultBinder, Type.EmptyTypes, null); Assert(toStringMethod != null); if (idAccess != null) { var toStringCall = Expression.Call(idAccess, toStringMethod); idGetAccessor = Expression.Lambda <Func <object, string> >(toStringCall, entityParameter).Compile(); } else { idGetAccessor = null; } }
private IInMemoryDatabase <TData> CreateTypedStore <TData>() where TData : class { var dataType = typeof(TData); var idType = DataPropertyHelper.GetIdType <TData>(); if (idType == null) { throw new Exception($"Cannot store objects of type '{typeof(TData).FullName}'. An id cannot be extracted."); // TODO } var typedStore = Activator.CreateInstance(typeof(InMemoryDatabase <,>).MakeGenericType(idType, dataType)); return((IInMemoryDatabase <TData>)typedStore); }