/// <summary>
 /// Caches an instance of a type as a type of <paramref name="type"/>. This instance will be returned each time you <see cref="Get(Type)"/>.
 /// </summary>
 /// <param name="type">The type to cache <paramref name="instance"/> as.</param>
 /// <param name="instance">The instance to cache. Must be or derive from <paramref name="type"/>.</param>
 /// <param name="info">Extra information to identify <paramref name="instance"/> in the cache.</param>
 public void CacheAs <T>(Type type, T instance, CacheInfo info) where T : class
 => CacheAs(type, info, instance, false);
Beispiel #2
0
        private static Func <IReadOnlyDependencyContainer, object> getDependency(Type type, Type requestingType, bool permitNulls, CacheInfo info) => dc =>
        {
            object val = dc.Get(type, info);
            if (val == null && !permitNulls)
            {
                throw new DependencyNotRegisteredException(requestingType, type);
            }

            if (val is IBindable bindableVal)
            {
                return(bindableVal.GetBoundCopy());
            }

            return(val);
        };
 public TypeAlreadyCachedException(CacheInfo info)
     : base($"An instance of the member ({info.ToString()}) has already been cached to the dependency container.")
 {
 }
 /// <summary>
 /// Caches an instance of a type as its most derived type. This instance will be returned each time you <see cref="Get(Type)"/>.
 /// </summary>
 /// <param name="instance">The instance to cache.</param>
 /// <param name="info">Extra information to identify <paramref name="instance"/> in the cache.</param>
 public void Cache(object instance, CacheInfo info)
 => CacheAs(instance.GetType(), info, instance, false);
 /// <summary>
 /// Caches an instance of a type as a type of <typeparamref name="T"/>. This instance will be returned each time you <see cref="DependencyContainer.Get(Type)"/>.
 /// </summary>
 /// <remarks>
 /// This should only be used when it is guaranteed that the internal state of the type will remain consistent through retrieval.
 /// (e.g. <see cref="CancellationToken"/> or reference types).
 /// </remarks>
 /// <param name="instance">The instance to cache. Must be or derive from <typeparamref name="T"/>.</param>
 /// <param name="info">Extra information to identify <paramref name="instance"/> in the cache.</param>
 internal void CacheValueAs <T>(T instance, CacheInfo info)
 => CacheAs(typeof(T), info, instance, true);
Beispiel #6
0
        private IReadOnlyDependencyContainer mergeDependencies(object obj, IReadOnlyDependencyContainer dependencies, CacheInfo info)
        {
            dependencies = baseActivator?.mergeDependencies(obj, dependencies, info) ?? dependencies;
            foreach (var a in buildCacheActivators)
            {
                dependencies = a(obj, dependencies, info);
            }

            return(dependencies);
        }
Beispiel #7
0
 /// <summary>
 /// Merges existing dependencies with new dependencies from an object into a new <see cref="IReadOnlyDependencyContainer"/>.
 /// </summary>
 /// <param name="obj">The object whose dependencies should be merged into the dependencies provided by <paramref name="dependencies"/>.</param>
 /// <param name="dependencies">The existing dependencies.</param>
 /// <param name="info">Extra information to identify parameters of <paramref name="obj"/> in the cache with.</param>
 /// <returns>A new <see cref="IReadOnlyDependencyContainer"/> if <paramref name="obj"/> provides any dependencies, otherwise <paramref name="dependencies"/>.</returns>
 public static IReadOnlyDependencyContainer MergeDependencies(object obj, IReadOnlyDependencyContainer dependencies, CacheInfo info = default)
 => getActivator(obj.GetType()).mergeDependencies(obj, dependencies, info);
Beispiel #8
0
        private static IEnumerable <Action <object, DependencyContainer, CacheInfo> > createMemberActivator(MemberInfo member, Type type, bool allowValueTypes)
        {
            switch (member)
            {
            case PropertyInfo pi:
            {
                var getMethod = pi.GetMethod;
                if (getMethod == null)
                {
                    throw new AccessModifierNotAllowedForCachedValueException(AccessModifier.None, pi);
                }

                if (getMethod.GetCustomAttribute <CompilerGeneratedAttribute>() == null)
                {
                    throw new AccessModifierNotAllowedForCachedValueException(AccessModifier.None, pi);
                }

                var setMethod = pi.SetMethod;

                if (setMethod != null)
                {
                    var modifier = setMethod.GetAccessModifier();
                    if (modifier != AccessModifier.Private)
                    {
                        throw new AccessModifierNotAllowedForCachedValueException(modifier, setMethod);
                    }

                    if (setMethod.GetCustomAttribute <CompilerGeneratedAttribute>() == null)
                    {
                        throw new AccessModifierNotAllowedForCachedValueException(AccessModifier.None, pi);
                    }
                }

                break;
            }

            case FieldInfo fi:
            {
                var modifier = fi.GetAccessModifier();
                if (modifier != AccessModifier.Private && !fi.IsInitOnly)
                {
                    throw new AccessModifierNotAllowedForCachedValueException(modifier, fi);
                }

                break;
            }
            }

            foreach (var attribute in member.GetCustomAttributes <CachedAttribute>())
            {
                yield return((target, dc, info) =>
                {
                    object value = null;

                    if (member is PropertyInfo p)
                    {
                        value = p.GetValue(target);
                    }

                    if (member is FieldInfo f)
                    {
                        value = f.GetValue(target);
                    }

                    if (value == null)
                    {
                        if (allowValueTypes)
                        {
                            return;
                        }

                        throw new NullDependencyException($"Attempted to cache a null value: {type.ReadableName()}.{member.Name}.");
                    }

                    var cacheInfo = new CacheInfo(info.Name ?? attribute.Name);

                    if (info.Parent != null)
                    {
                        // When a parent type exists, infer the property name if one is not provided
                        cacheInfo = new CacheInfo(cacheInfo.Name ?? member.Name, info.Parent);
                    }

                    dc.CacheAs(attribute.Type ?? value.GetType(), cacheInfo, value, allowValueTypes);
                });
            }
        }
Beispiel #9
0
 /// <summary>
 /// Retrieves a cached dependency of type <typeparamref name="T"/> if it exists, and null otherwise.
 /// </summary>
 /// <typeparam name="T">The dependency type to query for.</typeparam>
 /// <param name="container">The <see cref="IReadOnlyDependencyContainer"/> to query.</param>
 /// <param name="info">Extra information that identifies the cached dependency.</param>
 /// <returns>The requested dependency, or null if not found.</returns>
 public static T Get <T>(this IReadOnlyDependencyContainer container, CacheInfo info)
     where T : class
 => (T)container.Get(typeof(T), info);