public ITypeDescription DescribeType(Type type)
        {
            var memberTypeDescription = (ITypeDescription)null;

            using (var readLock = TypeDescriptionCacheLock.AcquireReadLock())
            {
                if (TypeDescriptionCache.TryGetValue(type.AssemblyQualifiedName, out memberTypeDescription))
                    return memberTypeDescription;
            }

            using (var writeLock = TypeDescriptionCacheLock.AcquireWriteLock())
            {
                if (TypeDescriptionCache.TryGetValue(type.AssemblyQualifiedName, out memberTypeDescription))
                    return memberTypeDescription;

                if (type.ImplementsInterface(typeof(IEnumerable)))
                {
                    memberTypeDescription = new ReflectionBasedEnumerableTypeDescription();
                }
                else
                {
                    memberTypeDescription = new ReflectionBasedTypeDescription();
                }

                // memberTypeDescription is now a prototype only (not populated)
                // add it to Type Description Cache, so if it's self refrencing it can be resolved
                // Describe it in a separate step while still holding write lock
                TypeDescriptionCache.Add(type.AssemblyQualifiedName, memberTypeDescription);

                memberTypeDescription = DescribeTypeInternal(type, memberTypeDescription as ReflectionBasedTypeDescription);
            }

            return memberTypeDescription;
        }
        public ILBasedTypeDescription(ReflectionBasedTypeDescription source)
        {
            this.Source = source;

            if(source.ParameterLessConstructorInfo != null)
                this.CreateInstanceDelegate = source.ParameterLessConstructorInfo.EmitConstructorInvocationDelegate();
            else if(source.Type.IsValueType || source.Type.IsEnum)
                this.CreateInstanceDelegate = source.Type.EmitConstructorInvocationDelegate();
        }        
        protected override ITypeDescription DescribeTypeInternal(Type type, ReflectionBasedTypeDescription typeDescription)
        {
            var description = base.DescribeTypeInternal(type, typeDescription) as ReflectionBasedTypeDescription;

            var oldMembers = description.Members;

            var newMembers = new TypeMemberDescriptionCollection();

            for (int i = 0; i < oldMembers.Count; i++)
            {
                var m = description.Members[i] as ReflectionBasedTypeMemberDescription;

                newMembers.Add(new ILBasedTypeMemberDescription(m));
            }

            description.Members = newMembers;

            if (description is ReflectionBasedEnumerableTypeDescription)
                return new ILBasedEnumerableTypeDescription(description as ReflectionBasedEnumerableTypeDescription);
            else
                return new ILBasedTypeDescription(description as ReflectionBasedTypeDescription);
        }
        protected virtual ITypeDescription DescribeTypeInternal(Type type, ReflectionBasedTypeDescription typeDescription)
        {
            if (type.ImplementsInterface(typeof(IEnumerable)))
            {
                var enumerableTypeDescription = typeDescription as ReflectionBasedEnumerableTypeDescription;

                typeDescription = enumerableTypeDescription;

                var compatibleItemTypes = type.GetCompatibleItemTypes();

                foreach(var t in compatibleItemTypes)
                    enumerableTypeDescription.AddCompatibleItemType(t);

                // find min concrete type which could be used as an item
                enumerableTypeDescription.DefaultConcreteItemType =
                    (from t in compatibleItemTypes
                     where !t.IsInterface && !t.IsAbstract
                     select t).FirstOrDefault();

                var capacityProperty = type.GetProperty("Capacity");

                if (capacityProperty != null && capacityProperty.CanWrite)
                {
                    enumerableTypeDescription.CanSetCapacity = true;
                    enumerableTypeDescription.CapacityPropertyInfo = capacityProperty;
                }
            }

            typeDescription.AssemblyQualifiedName = type.AssemblyQualifiedName;
            typeDescription.FullName = type.FullName;
            typeDescription.Name = type.Name;
            typeDescription.Namespace = type.Namespace;
            typeDescription.Type = type;

            typeDescription.IsValueType = type.IsValueType;
            
            var properties =
                (from p in type.GetProperties(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
                 where p.GetIndexParameters().IsNullOrEmpty()
                 select p).ToArray();

            var fields = new List<FieldInfo>().ToArray();
            // todo: develop customizable filters which can be used to determine if field should be included or now
            // those should work in later part (down below) after member description is created but before it is added
                //(from f in type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
                // where !f.Name.EndsWith("_backingfield", StringComparison.InvariantCultureIgnoreCase)
                // select f).ToArray();
            
            // assume that all members are immutable
            // change to false if any field or property is of immutable type
            bool areAllMembersImmutable = true;

            var prototypeMembers = new TypeMemberDescriptionCollection();

            for (int i = 0; i < fields.Length; i++)
            {
                var f = fields[i];

                var md = new ReflectionBasedTypeMemberDescription(f);

                var member_type = f.FieldType;

                if (!member_type.IsPublic && !member_type.IsNestedPublic)
                    continue;

                if(!member_type.IsValueType)
                    areAllMembersImmutable = false;

                var memberTypeDescription = (ITypeDescription)null;

                if (member_type == type)
                {
                    memberTypeDescription = typeDescription;
                }
                else
                {
                    memberTypeDescription = DescribeType(member_type);
                }

                md.AssemblyQualifiedMemberTypeName = memberTypeDescription.AssemblyQualifiedName;
                md.MemberType = memberTypeDescription;

                md.Name = f.Name;
                md.SanitizedName = f.Name;

                // todo: handle readonly fields
                md.CanGetValue = true;
                md.CanSetValue = true;
                
                md.Visibility = GetMemberVisibility(f);

                md.DeclaringType = typeDescription;

                prototypeMembers.Add(md);
            }

            for (int i = 0; i < properties.Length; i++)
            {
                var p = properties[i];

                var md = new ReflectionBasedTypeMemberDescription(p);

                var member_type = p.PropertyType;

                if (member_type.FullName == null)
                    continue;

                if (!member_type.IsPublic && !member_type.IsNestedPublic)
                    continue;

                if(!member_type.IsValueType)
                    areAllMembersImmutable = false;

                var memberTypeDescription = (ITypeDescription) null;

                if (member_type == type)
                {
                    memberTypeDescription = typeDescription;
                }
                else
                {
                    memberTypeDescription = DescribeType(member_type);
                }

                md.MemberType = memberTypeDescription;

                var explicit_interface_separator_index = p.Name.IndexOf(".");

                if (explicit_interface_separator_index != -1)
                {
                    // this is an explicit interface implementation

                    md.IsExplicitInterfaceImplementation = true;
                    md.Name = p.Name;

                    //var interface_name = p.Name.Substring(0, explicit_interface_separator_index);

                    //var mapp

                    //foreach(var interf in member_type.GetInterfaces())
                    //{
                    //    foreach(var interf_property in interf.GetProperties())
                    //    {
                    //        var isMatch =
                    //            p.Name == interf_property.Name
                    //            && member_type == interf_property.PropertyType
                                
                    //    }
                    //}
                    
                }
                else
                {
                    md.Name = p.Name;
                }

                md.SanitizedName = p.Name;

                md.CanGetValue = p.CanRead;
                md.CanSetValue = p.CanWrite && p.SetMethod.IsPublic;

                md.Visibility = GetMemberVisibility(p);

                md.DeclaringType = typeDescription;

                prototypeMembers.Add(md);
            }

            typeDescription.Members = prototypeMembers;

            typeDescription.AreAllMembersImmutable = areAllMembersImmutable;

            return typeDescription;
        }