/// <summary>
        /// Creates the wrapper object property wrapper.
        /// </summary>
        private static PropertyDescriptor CreateWrapperObjectPropertyWrapper(TypeMetaData context, PropertyInfo property)
        {
            var actualReader = GetPropertyReader(property, context);
            var actualWriter = GetPropertyWriter(property, context);

            var reader = property.CanRead ? new Func <object, object>(o => actualReader.GetValue(o)) : null;
            var writer = property.CanWrite ? new Action <object, object>((o, v) => actualWriter.SetValue(o, v)) : null;

            var descriptor = new DelegatePropertyDescriptor(
                property.Name,
                property.DeclaringType,
                property.PropertyType,
                reader,
                writer
                );

            return(descriptor);
        }
        /// <summary>
        /// Creates the context.
        /// </summary>
        /// <returns></returns>
        public static TypeMetaData GetFor(Type wrapperObjectType, Type wrappedObjectType)
        {
            lock (ContextsLock)
            {
                if (Contexts.ContainsKey(wrapperObjectType))
                {
                    return(Contexts[wrapperObjectType]);
                }
                var result = new TypeMetaData();

                var propertyNames = new List <string>();
                foreach (var property in wrapperObjectType.GetProperties())
                {
                    if (property.GetCustomAttributes(true).Any(a =>
                                                               a is BrowsableAttribute attribute && attribute.Browsable == false))
                    {
                        continue;
                    }
                    result.PropertyDescriptors.Add(CreateWrapperObjectPropertyWrapper(result, property));
                    result.AllKnownProperties.Add(property);
                    propertyNames.Add(property.Name);
                }

                foreach (var property in wrappedObjectType.GetProperties())
                {
                    if (propertyNames.Contains(property.Name))
                    {
                        continue;
                    }
                    result.PropertyDescriptors.Add(CreateWrappedObjectPropertyWrapper(result, property));
                    result.AllKnownProperties.Add(property);
                }
                Contexts.Add(wrapperObjectType, result);
                return(Contexts[wrapperObjectType]);
            }
        }
        /// <summary>
        /// Gets the property writer.
        /// </summary>
        private static IDelegatePropertyWriter GetPropertyWriter(PropertyInfo property, TypeMetaData context)
        {
            var actualWriter = DelegatePropertyFactory.CreatePropertyWriter(property);

            if (actualWriter != null)
            {
                context.PropertyWriters.Add(property, actualWriter);
            }
            return(actualWriter);
        }