예제 #1
0
        public void Returns_HashSet_if_assignable()
        {
            var factory = new CollectionTypeFactory();

            Assert.Same(typeof(HashSet <Random>), factory.TryFindTypeToInstantiate(typeof(object), typeof(ICollection <Random>)));
            Assert.Same(typeof(HashSet <Random>), factory.TryFindTypeToInstantiate(typeof(object), typeof(ISet <Random>)));
        }
예제 #2
0
        public void Returns_given_type_if_public_parameterless_constructor_available()
        {
            var factory = new CollectionTypeFactory();

            Assert.Same(typeof(CustomHashSet), factory.TryFindTypeToInstantiate(typeof(CustomHashSet)));
            Assert.Same(typeof(CustomList), factory.TryFindTypeToInstantiate(typeof(CustomList)));
            Assert.Same(typeof(HashSet <Random>), factory.TryFindTypeToInstantiate(typeof(HashSet <Random>)));
            Assert.Same(typeof(List <Random>), factory.TryFindTypeToInstantiate(typeof(List <Random>)));
            Assert.Same(typeof(ObservableCollection <Random>), factory.TryFindTypeToInstantiate(typeof(ObservableCollection <Random>)));
        }
예제 #3
0
        public void Returns_null_when_no_usable_concrete_type_found()
        {
            var factory = new CollectionTypeFactory();

            Assert.Null(factory.TryFindTypeToInstantiate(typeof(object), typeof(PrivateConstructor)));
            Assert.Null(factory.TryFindTypeToInstantiate(typeof(object), typeof(InternalConstructor)));
            Assert.Null(factory.TryFindTypeToInstantiate(typeof(object), typeof(ProtectedConstructor)));
            Assert.Null(factory.TryFindTypeToInstantiate(typeof(object), typeof(NoParameterlessConstructor)));
            Assert.Null(factory.TryFindTypeToInstantiate(typeof(object), typeof(Abstract)));
            Assert.Null(factory.TryFindTypeToInstantiate(typeof(object), typeof(object)));
            Assert.Null(factory.TryFindTypeToInstantiate(typeof(object), typeof(Random)));
        }
예제 #4
0
    private static IClrCollectionAccessor CreateGeneric <TEntity, TCollection, TElement>(INavigationBase navigation)
        where TEntity : class
        where TCollection : class, IEnumerable <TElement>
        where TElement : class
    {
        var entityParameter = Expression.Parameter(typeof(TEntity), "entity");
        var valueParameter  = Expression.Parameter(typeof(TCollection), "collection");

        var memberInfoForRead = navigation.GetMemberInfo(forMaterialization: false, forSet: false);

        navigation.TryGetMemberInfo(forConstruction: false, forSet: true, out var memberInfoForWrite, out _);
        navigation.TryGetMemberInfo(forConstruction: true, forSet: true, out var memberInfoForMaterialization, out _);

        var memberAccessForRead = (Expression)Expression.MakeMemberAccess(entityParameter, memberInfoForRead);

        if (memberAccessForRead.Type != typeof(TCollection))
        {
            memberAccessForRead = Expression.Convert(memberAccessForRead, typeof(TCollection));
        }

        var getterDelegate = Expression.Lambda <Func <TEntity, TCollection> >(
            memberAccessForRead,
            entityParameter).Compile();

        Action <TEntity, TCollection>?setterDelegate = null;
        Action <TEntity, TCollection>?setterDelegateForMaterialization = null;
        Func <TEntity, Action <TEntity, TCollection>, TCollection>?createAndSetDelegate = null;
        Func <TCollection>?createDelegate = null;

        if (memberInfoForWrite != null)
        {
            setterDelegate = CreateSetterDelegate(entityParameter, memberInfoForWrite, valueParameter);
        }

        if (memberInfoForMaterialization != null)
        {
            setterDelegateForMaterialization = CreateSetterDelegate(entityParameter, memberInfoForMaterialization, valueParameter);
        }

        var concreteType = new CollectionTypeFactory().TryFindTypeToInstantiate(
            typeof(TEntity),
            typeof(TCollection),
            navigation.DeclaringEntityType.Model[CoreAnnotationNames.FullChangeTrackingNotificationsRequired] != null);

        if (concreteType != null)
        {
            var isHashSet = concreteType.IsGenericType && concreteType.GetGenericTypeDefinition() == typeof(HashSet <>);
            if (setterDelegate != null ||
                setterDelegateForMaterialization != null)
            {
                if (isHashSet)
                {
                    createAndSetDelegate = (Func <TEntity, Action <TEntity, TCollection>, TCollection>)_createAndSetHashSet
                                           .MakeGenericMethod(typeof(TEntity), typeof(TCollection), typeof(TElement))
                                           .CreateDelegate(typeof(Func <TEntity, Action <TEntity, TCollection>, TCollection>));
                }
                else if (IsObservableHashSet(concreteType))
                {
                    createAndSetDelegate = (Func <TEntity, Action <TEntity, TCollection>, TCollection>)_createAndSetObservableHashSet
                                           .MakeGenericMethod(typeof(TEntity), typeof(TCollection), typeof(TElement))
                                           .CreateDelegate(typeof(Func <TEntity, Action <TEntity, TCollection>, TCollection>));
                }
                else
                {
                    createAndSetDelegate = (Func <TEntity, Action <TEntity, TCollection>, TCollection>)_createAndSet
                                           .MakeGenericMethod(typeof(TEntity), typeof(TCollection), concreteType)
                                           .CreateDelegate(typeof(Func <TEntity, Action <TEntity, TCollection>, TCollection>));
                }
            }

            if (isHashSet)
            {
                createDelegate = (Func <TCollection>)_createHashSet
                                 .MakeGenericMethod(typeof(TCollection), typeof(TElement))
                                 .CreateDelegate(typeof(Func <TCollection>));
            }
            else if (IsObservableHashSet(concreteType))
            {
                createDelegate = (Func <TCollection>)_createObservableHashSet
                                 .MakeGenericMethod(typeof(TCollection), typeof(TElement))
                                 .CreateDelegate(typeof(Func <TCollection>));
            }
            else
            {
                createDelegate = (Func <TCollection>)_create
                                 .MakeGenericMethod(typeof(TCollection), concreteType)
                                 .CreateDelegate(typeof(Func <TCollection>));
            }
        }

        return(new ClrICollectionAccessor <TEntity, TCollection, TElement>(
                   navigation.Name,
                   getterDelegate,
                   setterDelegate,
                   setterDelegateForMaterialization,
                   createAndSetDelegate,
                   createDelegate));
        private IClrCollectionAccessor CreateGeneric <TEntity, TCollection, TElement>(INavigation navigation, MemberInfo memberInfo)
            where TEntity : class
            where TElement : class
            where TCollection : class, IEnumerable <TElement>
        {
            var entityParameter = Expression.Parameter(typeof(TEntity), "entity");
            var valueParameter  = Expression.Parameter(typeof(TCollection), "collection");

            var getterDelegate = Expression.Lambda <Func <TEntity, TCollection> >(
                Expression.MakeMemberAccess(
                    entityParameter,
                    memberInfo),
                entityParameter).Compile();

            Action <TEntity, TCollection> setterDelegate = null;
            Func <TEntity, Action <TEntity, TCollection>, TCollection> createAndSetDelegate = null;
            Func <TCollection> createDelegate = null;

            var setterMemberInfo = navigation.GetMemberInfo(forConstruction: false, forSet: true);

            if (setterMemberInfo != null)
            {
                setterDelegate = Expression.Lambda <Action <TEntity, TCollection> >(
                    Expression.Assign(
                        Expression.MakeMemberAccess(
                            entityParameter,
                            setterMemberInfo),
                        Expression.Convert(
                            valueParameter,
                            setterMemberInfo.GetMemberType())),
                    entityParameter,
                    valueParameter).Compile();
            }

            if (setterDelegate != null)
            {
                var concreteType = new CollectionTypeFactory().TryFindTypeToInstantiate(typeof(TEntity), typeof(TCollection));

                if (concreteType != null)
                {
                    createAndSetDelegate = new Func <TEntity, Action <TEntity, TCollection>, TCollection>((entity, setter) =>
                    {
                        var collection = (TCollection)Activator.CreateInstance(concreteType);
                        setterDelegate(entity, collection);
                        return(collection);
                    });

                    createDelegate = new Func <TCollection>(() => (TCollection)Activator.CreateInstance(concreteType));
                }
                else
                {
                    if (typeof(TCollection).IsAssignableFrom(typeof(IQueryable <TElement>)))
                    {
                        var primaryKey         = navigation.ForeignKey.PrincipalKey.Properties[0].Name;
                        var parameter          = Expression.Parameter(typeof(TElement), "x");
                        var primaryKeyProperty = typeof(TEntity).GetProperty(primaryKey, BindingFlags.Public | BindingFlags.Instance);
                        var navigationProperty = typeof(TElement).GetProperties(BindingFlags.Public | BindingFlags.Instance).Single(x => x.PropertyType == typeof(TEntity));
                        var foreignValue       = Expression.Property(Expression.Property(parameter, navigationProperty), primaryKeyProperty);
                        var includeParameter   = Expression.Parameter(typeof(TElement), "x");
                        var includeExpression  = Expression.Lambda <Func <TElement, TEntity> >(Expression.Property(includeParameter, navigationProperty), includeParameter);
                        return(new BorlandClrICollectionAccessor <TEntity, TCollection, TElement>(
                                   (entity) =>
                        {
                            var primaryValue = Expression.Property(Expression.Constant(entity), primaryKeyProperty);
                            var expression = Expression.Lambda <Func <TElement, bool> >(Expression.Equal(foreignValue, primaryValue), parameter);
                            return new BorlandQueryableCollection <TElement>(_context.Set <TElement>().Include(includeExpression).Where(expression), _context);
                        },
                                   () => new BorlandQueryableCollection <TElement>(_context.Set <TElement>(), _context)));
                    }
                }
            }

            return(new ClrICollectionAccessor <TEntity, TCollection, TElement>(
                       navigation.Name, getterDelegate, setterDelegate, createAndSetDelegate, createDelegate));
        }