ServiceDescriptor
Describes how to select a types service.
            
                using Castle.DynamicProxy.Internal;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace Castle.MicroKernel.Registration
{
    public class ServiceDescriptor
    {
        public delegate IEnumerable<Type> ServiceSelector (Type type, Type[] baseTypes);
        private readonly BasedOnDescriptor basedOnDescriptor;
        private ServiceSelector serviceSelector;
        internal ServiceDescriptor(BasedOnDescriptor basedOnDescriptor)
        {
            this.basedOnDescriptor = basedOnDescriptor;
        }
        public BasedOnDescriptor AllInterfaces()
        {
            return Select((Type t, Type[] b) => TypeUtil.GetAllInterfaces(t));
        }
        public BasedOnDescriptor Base()
        {
            return Select((Type t, Type[] b) => b);
        }
        public BasedOnDescriptor DefaultInterfaces()
        {
            return Select(delegate(Type type, Type[] base) {
                ServiceDescriptor serviceDescriptor = this;
                return from i in TypeUtil.GetAllInterfaces(type)
                where type.get_Name().Contains(serviceDescriptor.GetInterfaceName(i))
                select i;
            });
        }
        public BasedOnDescriptor FirstInterface()
        {
            return Select(delegate(Type type, Type[] base) {
                Type type2 = TypeExtensions.GetInterfaces(type).FirstOrDefault();
                if ((object)type2 == null)
                    return null;
                return new Type[1] {
                    type2
                };
            });
        }
        public BasedOnDescriptor FromInterface(Type implements)
        {
            return Select(delegate(Type type, Type[] baseTypes) {
                HashSet<Type> hashSet = new HashSet<Type>();
                if ((object)implements != null)
                    AddFromInterface(type, implements, hashSet);
                else {
                    foreach (Type implements2 in baseTypes) {
                        AddFromInterface(type, implements2, hashSet);
                    }
                }
                if (hashSet.Count == 0) {
                    foreach (Type item in from t in baseTypes
                    where (object)t != typeof(object)
                    select t) {
                        if (TypeExtensions.IsAssignableFrom(item, type)) {
                            hashSet.Add(item);
                            return hashSet;
                        }
                    }
                    return hashSet;
                }
                return hashSet;
            });
        }
        public BasedOnDescriptor FromInterface()
        {
            return FromInterface(null);
        }
        public BasedOnDescriptor Select(ServiceSelector selector)
        {
            serviceSelector = (ServiceSelector)Delegate.Combine(serviceSelector, selector);
            return basedOnDescriptor;
        }
        public BasedOnDescriptor Select(IEnumerable<Type> types)
        {
            return Select((Type <p0>, Type[] <p1>) => types);
        }
        public BasedOnDescriptor Self()
        {
            return Select((Type t, Type[] b) => new Type[1] {
                t
            });
        }
        internal ICollection<Type> GetServices(Type type, Type[] baseType)
        {
            HashSet<Type> hashSet = new HashSet<Type>();
            if (serviceSelector != null) {
                Delegate[] invocationList = serviceSelector.GetInvocationList();
                for (int i = 0; i < invocationList.Length; i++) {
                    IEnumerable<Type> enumerable = ((ServiceSelector)invocationList[i])(type, baseType);
                    if (enumerable != null) {
                        foreach (Type item in enumerable.Select(WorkaroundCLRBug)) {
                            hashSet.Add(item);
                        }
                    }
                }
            }
            return hashSet;
        }
        private void AddFromInterface(Type type, Type implements, ICollection<Type> matches)
        {
            foreach (Type topLevelInterface in GetTopLevelInterfaces(type)) {
                if ((object)topLevelInterface.GetTypeInfo().GetInterface(implements.FullName, false) != null)
                    matches.Add(topLevelInterface);
            }
        }
        private string GetInterfaceName(Type interface)
        {
            string name = interface.get_Name();
            if (name.Length > 1 && name[0] == 'I' && char.IsUpper(name[1]))
                return name.Substring(1);
            return name;
        }
        private IEnumerable<Type> GetTopLevelInterfaces(Type type)
        {
            Type[] interfaces = TypeExtensions.GetInterfaces(type);
            List<Type> list = new List<Type>(interfaces);
            Type[] array = interfaces;
            for (int i = 0; i < array.Length; i++) {
                Type[] interfaces2 = TypeExtensions.GetInterfaces(array[i]);
                foreach (Type item in interfaces2) {
                    list.Remove(item);
                }
            }
            return list;
        }
        private static Type WorkaroundCLRBug(Type serviceType)
        {
            if (!serviceType.GetTypeInfo().get_IsInterface())
                return serviceType;
            if (serviceType.GetTypeInfo().get_IsGenericType() && (object)serviceType.DeclaringType == null) {
                bool flag = false;
                Type[] genericArguments = TypeExtensions.GetGenericArguments(serviceType);
                foreach (Type type in genericArguments) {
                    flag |= type.IsGenericParameter;
                }
                if (flag)
                    return serviceType.GetGenericTypeDefinition();
            }
            return serviceType;
        }
    }
}