123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582 |
- /****************************************************************************
- * Copyright (c) 2018 ~ 2022 liangxiegame UNDER MIT License
- *
- * http://qframework.io
- * https://github.com/liangxiegame/QFramework
- ****************************************************************************/
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Reflection;
- namespace QFramework
- {
- /// <summary>
- /// Used by the injection container to determine if a property or field should be injected.
- /// </summary>
- [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
- public class InjectAttribute : Attribute
- {
- public InjectAttribute(string name)
- {
- Name = name;
- }
- public string Name { get; set; }
- public InjectAttribute()
- {
- }
- }
-
- public interface IQFrameworkContainer
- {
- /// <summary>
- /// Clears all type mappings and instances.
- /// </summary>
- void Clear();
- /// <summary>
- /// Injects registered types/mappings into an object
- /// </summary>
- /// <param name="obj"></param>
- void Inject(object obj);
- /// <summary>
- /// Injects everything that is registered at once
- /// </summary>
- void InjectAll();
- /// <summary>
- /// Register a type mapping
- /// </summary>
- /// <typeparam name="TSource">The base type.</typeparam>
- /// <typeparam name="TTarget">The concrete type</typeparam>
- void Register<TSource, TTarget>(string name = null);
- void RegisterRelation<TFor, TBase, TConcrete>();
- /// <summary>
- /// Register an instance of a type.
- /// </summary>
- /// <typeparam name="TBase"></typeparam>
- /// <param name="default"></param>
- /// <param name="injectNow"></param>
- /// <returns></returns>
- void RegisterInstance<TBase>(TBase @default, bool injectNow) where TBase : class;
- /// <summary>
- /// Register an instance of a type.
- /// </summary>
- /// <param name="type"></param>
- /// <param name="default"></param>
- /// <param name="injectNow"></param>
- /// <returns></returns>
- void RegisterInstance(Type type, object @default, bool injectNow);
- /// <summary>
- /// Register a named instance
- /// </summary>
- /// <param name="baseType">The type to register the instance for.</param>
- /// <param name="name">The name for the instance to be resolved.</param>
- /// <param name="instance">The instance that will be resolved be the name</param>
- /// <param name="injectNow">Perform the injection immediately</param>
- void RegisterInstance(Type baseType, object instance = null, string name = null, bool injectNow = true);
- void RegisterInstance<TBase>(TBase instance, string name, bool injectNow = true) where TBase : class;
- void RegisterInstance<TBase>(TBase instance) where TBase : class;
- /// <summary>
- /// If an instance of T exist then it will return that instance otherwise it will create a new one based off mappings.
- /// </summary>
- /// <typeparam name="T">The type of instance to resolve</typeparam>
- /// <returns>The/An instance of 'instanceType'</returns>
- T Resolve<T>(string name = null, bool requireInstance = false, params object[] args) where T : class;
- TBase ResolveRelation<TBase>(Type tfor, params object[] arg);
- TBase ResolveRelation<TFor, TBase>(params object[] arg);
- /// <summary>
- /// Resolves all instances of TType or subclasses of TType. Either named or not.
- /// </summary>
- /// <typeparam name="TType">The Type to resolve</typeparam>
- /// <returns>List of objects.</returns>
- IEnumerable<TType> ResolveAll<TType>();
- //IEnumerable<object> ResolveAll(Type type);
- void Register(Type source, Type target, string name = null);
- /// <summary>
- /// Resolves all instances of TType or subclasses of TType. Either named or not.
- /// </summary>
- /// <typeparam name="TType">The Type to resolve</typeparam>
- /// <returns>List of objects.</returns>
- IEnumerable<object> ResolveAll(Type type);
- TypeMappingCollection Mappings { get; set; }
- TypeInstanceCollection Instances { get; set; }
- TypeRelationCollection RelationshipMappings { get; set; }
- /// <summary>
- /// If an instance of instanceType exist then it will return that instance otherwise it will create a new one based off mappings.
- /// </summary>
- /// <param name="baseType">The type of instance to resolve</param>
- /// <param name="name">The type of instance to resolve</param>
- /// <param name="requireInstance">If true will return null if an instance isn't registered.</param>
- /// <returns>The/An instance of 'instanceType'</returns>
- object Resolve(Type baseType, string name = null, bool requireInstance = false,
- params object[] constructorArgs);
- object ResolveRelation(Type tfor, Type tbase, params object[] arg);
- void RegisterRelation(Type tfor, Type tbase, Type tconcrete);
- object CreateInstance(Type type, params object[] args);
- }
- /// <summary>
- /// A ViewModel Container and a factory for Controllers and commands.
- /// </summary>
- public class QFrameworkContainer : IQFrameworkContainer
- {
- private TypeInstanceCollection _instances;
- private TypeMappingCollection _mappings;
- public TypeMappingCollection Mappings
- {
- get { return _mappings ?? (_mappings = new TypeMappingCollection()); }
- set { _mappings = value; }
- }
- public TypeInstanceCollection Instances
- {
- get { return _instances ?? (_instances = new TypeInstanceCollection()); }
- set { _instances = value; }
- }
- public TypeRelationCollection RelationshipMappings
- {
- get { return _relationshipMappings; }
- set { _relationshipMappings = value; }
- }
- public IEnumerable<TType> ResolveAll<TType>()
- {
- foreach (var obj in ResolveAll(typeof(TType)))
- {
- yield return (TType) obj;
- }
- }
- /// <summary>
- /// Resolves all instances of TType or subclasses of TType. Either named or not.
- /// </summary>
- /// <typeparam name="TType">The Type to resolve</typeparam>
- /// <returns>List of objects.</returns>
- public IEnumerable<object> ResolveAll(Type type)
- {
- foreach (KeyValuePair<Tuple<Type, string>, object> kv in Instances)
- {
- if (kv.Key.Item1 == type && !string.IsNullOrEmpty(kv.Key.Item2))
- yield return kv.Value;
- }
- foreach (KeyValuePair<Tuple<Type, string>, Type> kv in Mappings)
- {
- if (!string.IsNullOrEmpty(kv.Key.Item2))
- {
- #if NETFX_CORE
- var condition = type.GetTypeInfo().IsSubclassOf(mapping.From);
- #else
- var condition = type.IsAssignableFrom(kv.Key.Item1);
- #endif
- if (condition)
- {
- var item = Activator.CreateInstance(kv.Value);
- Inject(item);
- yield return item;
- }
- }
- }
- }
- /// <summary>
- /// Clears all type-mappings and instances.
- /// </summary>
- public void Clear()
- {
- Instances.Clear();
- Mappings.Clear();
- RelationshipMappings.Clear();
- }
- /// <summary>
- /// Injects registered types/mappings into an object
- /// </summary>
- /// <param name="obj"></param>
- public void Inject(object obj)
- {
- if (obj == null) return;
- #if !NETFX_CORE
- var members = obj.GetType().GetMembers();
- #else
- var members = obj.GetType().GetTypeInfo().DeclaredMembers;
- #endif
- foreach (var memberInfo in members)
- {
- var injectAttribute =
- memberInfo.GetCustomAttributes(typeof(InjectAttribute), true).FirstOrDefault() as InjectAttribute;
- if (injectAttribute != null)
- {
- if (memberInfo is PropertyInfo)
- {
- var propertyInfo = memberInfo as PropertyInfo;
- propertyInfo.SetValue(obj, Resolve(propertyInfo.PropertyType, injectAttribute.Name), null);
- }
- else if (memberInfo is FieldInfo)
- {
- var fieldInfo = memberInfo as FieldInfo;
- fieldInfo.SetValue(obj, Resolve(fieldInfo.FieldType, injectAttribute.Name));
- }
- }
- }
- }
- /// <summary>
- /// Register a type mapping
- /// </summary>
- /// <typeparam name="TSource">The base type.</typeparam>
- /// <typeparam name="TTarget">The concrete type</typeparam>
- public void Register<TSource>(string name = null)
- {
- Mappings[typeof(TSource), name] = typeof(TSource);
- }
- /// <summary>
- /// Register a type mapping
- /// </summary>
- /// <typeparam name="TSource">The base type.</typeparam>
- /// <typeparam name="TTarget">The concrete type</typeparam>
- public void Register<TSource, TTarget>(string name = null)
- {
- Mappings[typeof(TSource), name] = typeof(TTarget);
- }
- public void Register(Type source, Type target, string name = null)
- {
- Mappings[source, name] = target;
- }
- /// <summary>
- /// Register a named instance
- /// </summary>
- /// <param name="baseType">The type to register the instance for.</param>
- /// <param name="instance">The instance that will be resolved be the name</param>
- /// <param name="injectNow">Perform the injection immediately</param>
- public void RegisterInstance(Type baseType, object instance = null, bool injectNow = true)
- {
- RegisterInstance(baseType, instance, null, injectNow);
- }
- /// <summary>
- /// Register a named instance
- /// </summary>
- /// <param name="baseType">The type to register the instance for.</param>
- /// <param name="name">The name for the instance to be resolved.</param>
- /// <param name="instance">The instance that will be resolved be the name</param>
- /// <param name="injectNow">Perform the injection immediately</param>
- public virtual void RegisterInstance(Type baseType, object instance = null, string name = null,
- bool injectNow = true)
- {
- Instances[baseType, name] = instance;
- if (injectNow)
- {
- Inject(instance);
- }
- }
- public void RegisterInstance<TBase>(TBase instance) where TBase : class
- {
- RegisterInstance<TBase>(instance, true);
- }
- public void RegisterInstance<TBase>(TBase instance, bool injectNow) where TBase : class
- {
- RegisterInstance<TBase>(instance, null, injectNow);
- }
- public void RegisterInstance<TBase>(TBase instance, string name, bool injectNow = true) where TBase : class
- {
- RegisterInstance(typeof(TBase), instance, name, injectNow);
- }
- /// <summary>
- /// If an instance of T exist then it will return that instance otherwise it will create a new one based off mappings.
- /// </summary>
- /// <typeparam name="T">The type of instance to resolve</typeparam>
- /// <returns>The/An instance of 'instanceType'</returns>
- public T Resolve<T>(string name = null, bool requireInstance = false, params object[] args) where T : class
- {
- return (T) Resolve(typeof(T), name, requireInstance, args);
- }
- /// <summary>
- /// If an instance of instanceType exist then it will return that instance otherwise it will create a new one based off mappings.
- /// </summary>
- /// <param name="baseType">The type of instance to resolve</param>
- /// <param name="name">The type of instance to resolve</param>
- /// <param name="requireInstance">If true will return null if an instance isn't registered.</param>
- /// <param name="constructorArgs">The arguments to pass to the constructor if any.</param>
- /// <returns>The/An instance of 'instanceType'</returns>
- public object Resolve(Type baseType, string name = null, bool requireInstance = false,
- params object[] constructorArgs)
- {
- // Look for an instance first
- var item = Instances[baseType, name];
- if (item != null)
- {
- return item;
- }
- if (requireInstance)
- return null;
- // Check if there is a mapping of the type
- var namedMapping = Mappings[baseType, name];
- if (namedMapping != null)
- {
- var obj = CreateInstance(namedMapping, constructorArgs);
- //Inject(obj);
- return obj;
- }
- return null;
- }
- public object CreateInstance(Type type, params object[] constructorArgs)
- {
- if (constructorArgs != null && constructorArgs.Length > 0)
- {
- //return Activator.CreateInstance(type,BindingFlags.Public | BindingFlags.Instance,Type.DefaultBinder, constructorArgs,CultureInfo.CurrentCulture);
- var obj2 = Activator.CreateInstance(type, constructorArgs);
- Inject(obj2);
- return obj2;
- }
- #if !NETFX_CORE
- ConstructorInfo[] constructor = type.GetConstructors(BindingFlags.Public | BindingFlags.Instance);
- #else
- ConstructorInfo[] constructor = type.GetTypeInfo().DeclaredConstructors.ToArray();
- #endif
- if (constructor.Length < 1)
- {
- var obj2 = Activator.CreateInstance(type);
- Inject(obj2);
- return obj2;
- }
- var maxParameters = constructor.First().GetParameters();
- foreach (var c in constructor)
- {
- var parameters = c.GetParameters();
- if (parameters.Length > maxParameters.Length)
- {
- maxParameters = parameters;
- }
- }
- var args = maxParameters.Select(p =>
- {
- if (p.ParameterType.IsArray)
- {
- return ResolveAll(p.ParameterType);
- }
- return Resolve(p.ParameterType) ?? Resolve(p.ParameterType, p.Name);
- }).ToArray();
- var obj = Activator.CreateInstance(type, args);
- Inject(obj);
- return obj;
- }
- public TBase ResolveRelation<TBase>(Type tfor, params object[] args)
- {
- try
- {
- return (TBase) ResolveRelation(tfor, typeof(TBase), args);
- }
- catch (InvalidCastException castIssue)
- {
- throw new Exception(
- string.Format("Resolve Relation couldn't cast to {0} from {1}", typeof(TBase).Name, tfor.Name),
- castIssue);
- }
- }
- public void InjectAll()
- {
- foreach (object instance in Instances.Values)
- {
- Inject(instance);
- }
- }
- private TypeRelationCollection _relationshipMappings = new TypeRelationCollection();
- public void RegisterRelation<TFor, TBase, TConcrete>()
- {
- RelationshipMappings[typeof(TFor), typeof(TBase)] = typeof(TConcrete);
- }
- public void RegisterRelation(Type tfor, Type tbase, Type tconcrete)
- {
- RelationshipMappings[tfor, tbase] = tconcrete;
- }
- public object ResolveRelation(Type tfor, Type tbase, params object[] args)
- {
- var concreteType = RelationshipMappings[tfor, tbase];
- if (concreteType == null)
- {
- return null;
- }
- var result = CreateInstance(concreteType, args);
- //Inject(result);
- return result;
- }
- public TBase ResolveRelation<TFor, TBase>(params object[] arg)
- {
- return (TBase) ResolveRelation(typeof(TFor), typeof(TBase), arg);
- }
- }
- // http://stackoverflow.com/questions/1171812/multi-key-dictionary-in-c
- public class Tuple<T1, T2> //FUCKING Unity: struct is not supported in Mono
- {
- public readonly T1 Item1;
- public readonly T2 Item2;
- public Tuple(T1 item1, T2 item2)
- {
- Item1 = item1;
- Item2 = item2;
- }
- public override bool Equals(Object obj)
- {
- Tuple<T1, T2> p = obj as Tuple<T1, T2>;
- if (obj == null) return false;
- if (Item1 == null)
- {
- if (p.Item1 != null) return false;
- }
- else
- {
- if (p.Item1 == null || !Item1.Equals(p.Item1)) return false;
- }
- if (Item2 == null)
- {
- if (p.Item2 != null) return false;
- }
- else
- {
- if (p.Item2 == null || !Item2.Equals(p.Item2)) return false;
- }
- return true;
- }
- public override int GetHashCode()
- {
- int hash = 0;
- if (Item1 != null)
- hash ^= Item1.GetHashCode();
- if (Item2 != null)
- hash ^= Item2.GetHashCode();
- return hash;
- }
- }
- // Kanglai: Using Dictionary rather than List!
- public class TypeMappingCollection : Dictionary<Tuple<Type, string>, Type>
- {
- public Type this[Type from, string name = null]
- {
- get
- {
- Tuple<Type, string> key = new Tuple<Type, string>(from, name);
- Type mapping = null;
- if (this.TryGetValue(key, out mapping))
- {
- return mapping;
- }
- return null;
- }
- set
- {
- Tuple<Type, string> key = new Tuple<Type, string>(from, name);
- this[key] = value;
- }
- }
- }
- public class TypeInstanceCollection : Dictionary<Tuple<Type, string>, object>
- {
- public object this[Type from, string name = null]
- {
- get
- {
- Tuple<Type, string> key = new Tuple<Type, string>(from, name);
- object mapping = null;
- if (this.TryGetValue(key, out mapping))
- {
- return mapping;
- }
- return null;
- }
- set
- {
- Tuple<Type, string> key = new Tuple<Type, string>(from, name);
- this[key] = value;
- }
- }
- }
- public class TypeRelationCollection : Dictionary<Tuple<Type, Type>, Type>
- {
- public Type this[Type from, Type to]
- {
- get
- {
- Tuple<Type, Type> key = new Tuple<Type, Type>(from, to);
- Type mapping = null;
- if (this.TryGetValue(key, out mapping))
- {
- return mapping;
- }
- return null;
- }
- set
- {
- Tuple<Type, Type> key = new Tuple<Type, Type>(from, to);
- this[key] = value;
- }
- }
- }
- }
|