using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Xml.Serialization; using Unity.Injection; namespace Implab.ServiceHost.Unity { public class InjectionParameterBuilder { readonly TypeResolver m_resolver; public Type DefaultType { get; private set; } public Type ValueType { get; private set; } object m_value; public object Value { get { if (!ValueSpecified) throw new InvalidOperationException("The regular value must be set (dependency or array are not situable in this context)"); return m_value; } } public bool ValueSpecified { get; private set; } InjectionParameterValue m_injection; public InjectionParameterValue Injection { get { if (m_injection == null) throw new InvalidOperationException("The injection parameter is not specified"); return m_injection; } } public bool InjectionSpecified { get { return m_injection != null; } } internal InjectionParameterBuilder(TypeResolver resolver, Type defaultType) { m_resolver = resolver; DefaultType = defaultType; } public Type ResolveInjectedValueType(string typeSpec) { if (string.IsNullOrEmpty(typeSpec)) { if (DefaultType == null) throw new Exception("The type must be specified"); return DefaultType; } return m_resolver.Resolve(typeSpec, true); } public Type ResolveType(string typeSpec) { return string.IsNullOrEmpty(typeSpec) ? null : m_resolver.Resolve(typeSpec, true); } public void SetValue(Type type, object value) { Safe.ArgumentNotNull(type, nameof(type)); ValueType = type; m_value = value; ValueSpecified = true; m_injection = new InjectionParameter(type, value); } public void SetDependency(Type type, string name, bool optional) { Safe.ArgumentNotNull(type, nameof(type)); ValueType = type; ValueSpecified = false; m_value = null; m_injection = optional ? (InjectionParameterValue)new OptionalParameter(type, name) : new ResolvedParameter(type, name); } internal void Visit(ArrayParameterElement arrayParameter) { Type itemsType = null; var arrayType = string.IsNullOrEmpty(arrayParameter.TypeName) ? null : ResolveType(arrayParameter.TypeName); if (arrayType == null) arrayType = DefaultType; if (!string.IsNullOrEmpty(arrayParameter.ItemsType)) { itemsType = ResolveType(arrayParameter.ItemsType); arrayType = itemsType.MakeArrayType(); } else { itemsType = GetItemsType(arrayType); } if (itemsType == null) throw new Exception("Failed to determine array elements type"); InjectionParameterValue[] injections = (arrayParameter.Items ?? new AbstractInjectionParameter[0]) .Select(x => { var builder = new InjectionParameterBuilder(m_resolver, itemsType); x.Visit(builder); return builder.Injection; }) .ToArray(); var array = itemsType.IsGenericParameter ? (InjectionParameterValue)new GenericResolvedArrayParameter(itemsType.Name, injections) : new ResolvedArrayParameter(itemsType, injections); ValueType = arrayType; m_value = null; ValueSpecified = false; m_injection = array; } Type GetItemsType(Type collectionType) { if (collectionType == null) return null; Type itemsType = null; if (collectionType.GetGenericTypeDefinition() == typeof(IEnumerable<>)) { itemsType = collectionType.GetGenericArguments()[0]; } else if (collectionType == typeof(IEnumerable)) { itemsType = typeof(object); } else { itemsType = collectionType.GetInterface(typeof(IEnumerable<>).FullName)?.GetGenericArguments()[0]; } return itemsType; } } }