private static void CreatePropertySetterDelegate(Builder builder, PropertyBuilderInfo member, Method propertySetter)
        {
            // If we don't have a backing field and we don't have a setter and getter
            // don't bother creating a setter delegate
            if (member.Property.BackingField == null && propertySetter == null)
            {
                return;
            }

            if (member.Property.BackingField == null && member.Property.Getter != null && member.Property.Setter != null)
            {
                var getter = member.Property.Getter.Copy();
                var setter = member.Property.Setter.Copy();

                CreateSetterDelegate(builder, propertySetter, member.Property.ReturnType,
                                     x => x.Call(getter.IsStatic ? null : Crumb.This, getter),
                                     (coder, value) => coder.Call(setter.IsStatic ? null : Crumb.This, setter, value()));
            }
            else if (member.Property.BackingField != null && !member.Property.BackingField.FieldType.IsGenericType)
            {
                CreateSetterDelegate(builder, propertySetter, member.Property.BackingField.FieldType,
                                     x => x.Load(member.Property.BackingField) as ICode,
                                     (coder, value) => coder.Assign(member.Property.BackingField).Set(value()));
            }
            else if (member.Property.BackingField == null && member.Property.Setter != null)
            {
                var methodSetter = member.Property.Setter.Copy();
                propertySetter.NewCode().Call(methodSetter.IsStatic ? null : Crumb.This, methodSetter, Crumb.GetParameter(0)).Return().Replace();
            }
            else if (member.Property.BackingField == null && member.Property.Getter != null)
            {
                // This shouldn't be a thing
            }
            else
            {
                propertySetter.NewCode().Assign(member.Property.BackingField).Set(Crumb.GetParameter(0)).Return().Replace();
            }
        }
        private static void AddPropertySetterInterception(Builder builder, __PropertyInterceptionInfo propertyInterceptionInfo, PropertyBuilderInfo member, Field propertyField, Method actionObjectCtor, Method propertySetter, Dictionary <string, Field> interceptorFields)
        {
            var syncRoot = new __ISyncRoot(builder);
            var legalSetterInterceptors = member.InterceptorInfos.Where(x => x.InterfaceSetter != null).ToArray();

            member.Property.Setter
            .NewCode()
            .Context(x =>
            {
                for (int i = 0; i < legalSetterInterceptors.Length; i++)
                {
                    var item  = legalSetterInterceptors[i];
                    var field = interceptorFields[item.Attribute.Identification];
                    x.Load(field).IsNull().Then(y =>
                    {
                        y.Assign(field).NewObj(item.Attribute);

                        if (item.HasSyncRootInterface)
                        {
                            y.Load(field).As(syncRoot.Type.Import()).Call(syncRoot.SyncRoot, member.SyncRoot);
                        }
                    });
                    item.Attribute.Remove();
                }

                x.Load(propertyField).IsNull().Then(y =>
                                                    y.Assign(propertyField)
                                                    .NewObj(propertyInterceptionInfo.Ctor,
                                                            member.Property.Getter,
                                                            member.Property.Setter,
                                                            member.Property.Name,
                                                            member.Property.ReturnType,
                                                            y.This,
                                                            member.Property.ReturnType.IsArray || member.Property.ReturnType.Implements(typeof(IEnumerable)) ? member.Property.ReturnType.ChildType : null,
                                                            y.NewCode().NewObj(actionObjectCtor, propertySetter)));
            })
            .Try(x =>
            {
                for (int i = 0; i < legalSetterInterceptors.Length; i++)
                {
                    var item  = legalSetterInterceptors[i];
                    var field = interceptorFields[item.Attribute.Identification];
                    x.Load(field).As(legalSetterInterceptors[i].InterfaceSetter.Type).Call(item.InterfaceSetter.OnSet, propertyField, member.Property.BackingField, member.Property.Setter.NewCode().GetParameter(0));

                    x.IsFalse().Then(y => y.Assign(member.Property.BackingField).Set(member.Property.Setter.NewCode().GetParameter(0)));
                }
            })
            .Catch(typeof(Exception), x =>
            {
                for (int i = 0; i < legalSetterInterceptors.Length; i++)
                {
                    var item  = legalSetterInterceptors[i];
                    var field = interceptorFields[item.Attribute.Identification];
                    x.Load(field).As(legalSetterInterceptors[i].InterfaceSetter.Type).Call(legalSetterInterceptors[i].InterfaceSetter.OnException, x.Exception);
                }

                x.Rethrow();
            })
            .Finally(x =>
            {
                for (int i = 0; i < legalSetterInterceptors.Length; i++)
                {
                    var item  = legalSetterInterceptors[i];
                    var field = interceptorFields[item.Attribute.Identification];
                    x.Load(field).As(legalSetterInterceptors[i].InterfaceSetter.Type).Call(legalSetterInterceptors[i].InterfaceSetter.OnExit);
                }
            })
            .EndTry()
            .Return()
            .Replace();
        }
        private static void CreatePropertySetterDelegate(Builder builder, PropertyBuilderInfo member, Method propertySetter)
        {
            var iList      = new __IList(builder);
            var setterCode = propertySetter.NewCode();

            if (!member.Property.BackingField.FieldType.IsGenericType)
            {
                var extensions = new __Extensions(builder);

                if (member.Property.BackingField.FieldType.ParameterlessContructor != null && member.Property.BackingField.FieldType.ParameterlessContructor.IsPublic)
                {
                    setterCode.Load(member.Property.BackingField).IsNull().Then(y =>
                                                                                y.Assign(member.Property.BackingField).Set(propertySetter.NewCode()
                                                                                                                           .NewObj(member.Property.BackingField.FieldType.ParameterlessContructor)));
                }

                // Only this if the property implements idisposable
                if (member.Property.BackingField.FieldType.Implements(typeof(IDisposable)))
                {
                    setterCode.Call(extensions.TryDisposeInternal, member.Property.BackingField);
                }

                setterCode.Load(propertySetter.NewCode().GetParameter(0)).IsNull().Then(x =>
                {
                    // Just clear if its clearable
                    if (member.Property.BackingField.FieldType.Implements(iList.Type.Fullname))
                    {
                        x.Load(member.Property.BackingField).Callvirt(iList.Clear).Return();
                    }
                    // Otherwise if the property is not a value type and nullable
                    else if (!member.Property.BackingField.FieldType.IsValueType || member.Property.BackingField.FieldType.IsNullable || member.Property.BackingField.FieldType.IsArray)
                    {
                        x.Assign(member.Property.BackingField).Set(null).Return();
                    }
                    else // otherwise... throw an exception
                    {
                        x.ThrowNew(typeof(NotSupportedException), "Value types does not accept null values.");
                    }
                });

                if (member.Property.BackingField.FieldType.IsArray)
                {
                    setterCode.Load(propertySetter.NewCode().GetParameter(0)).Is(typeof(IEnumerable))
                    .Then(x => x.Assign(member.Property.BackingField).Set(propertySetter.NewCode().GetParameter(0)).Return())
                    .ThrowNew(typeof(NotSupportedException), "Value does not inherits from IEnumerable");
                }
                else if (member.Property.BackingField.FieldType.Implements(iList.Type.Fullname) && member.Property.BackingField.FieldType.ParameterlessContructor != null)
                {
                    var addRange = member.Property.BackingField.FieldType.GetMethod("AddRange", 1, false);
                    if (addRange == null)
                    {
                        var add   = member.Property.BackingField.FieldType.GetMethod("Add", 1);
                        var array = setterCode.CreateVariable(member.Property.BackingField.FieldType.ChildType.MakeArray());
                        setterCode.Assign(array).Set(propertySetter.NewCode().GetParameter(0));
                        setterCode.For(array, (x, item) => x.Load(member.Property.BackingField).Callvirt(add, item));
                        if (!add.ReturnType.IsVoid)
                        {
                            setterCode.Pop();
                        }
                    }
                    else
                    {
                        setterCode.Load(member.Property.BackingField).Callvirt(addRange, propertySetter.NewCode().GetParameter(0));
                    }
                }
                else if (member.Property.BackingField.FieldType.IsEnum)
                {
                    // Enums requires special threatment
                    setterCode.Load(propertySetter.NewCode().GetParameter(0)).Is(typeof(string)).Then(x =>
                    {
                        var stringVariable = setterCode.CreateVariable(typeof(string));
                        setterCode.Assign(stringVariable).Set(x.NewCode().GetParameter(0));
                        setterCode.Assign(member.Property.BackingField).Set(stringVariable).Return();
                    });

                    setterCode.Assign(member.Property.BackingField).Set(propertySetter.NewCode().GetParameter(0));
                }
                else
                {
                    setterCode.Assign(member.Property.BackingField).Set(propertySetter.NewCode().GetParameter(0));
                }
            }
            else
            {
                setterCode.Assign(member.Property.BackingField).Set(propertySetter.NewCode().GetParameter(0));
            }

            setterCode.Return().Replace();
        }
        private static void AddPropertySetterInterception(Builder builder, __PropertyInterceptionInfo propertyInterceptionInfo, PropertyBuilderInfo member, Field propertyField, Method actionObjectCtor, Method propertySetter, Dictionary <string, Field> interceptorFields)
        {
            var syncRoot = new __ISyncRoot();
            var legalSetterInterceptors = member.InterceptorInfos.Where(x => x.InterfaceSetter != null).ToArray();

            member.Property.Setter
            .NewCode()
            .Context(x =>
            {
                if (member.HasInitializer)
                {
                    return;
                }

                for (int i = 0; i < legalSetterInterceptors.Length; i++)
                {
                    var item  = legalSetterInterceptors[i];
                    var field = interceptorFields[item.Attribute.Identification];
                    x.Load(field).IsNull().Then(y =>
                    {
                        y.Assign(field).NewObj(item.Attribute);

                        if (item.HasSyncRootInterface)
                        {
                            y.Load(field).As(syncRoot.ToBuilderType.Import()).Call(syncRoot.SyncRoot, member.SyncRoot);
                        }

                        ImplementAssignMethodAttribute(builder, legalSetterInterceptors[i].AssignMethodAttributeInfos, field, y, false);
                    });
                    item.Attribute.Remove();
                }

                x.Load(propertyField).IsNull().Then(y =>
                                                    y.Assign(propertyField)
                                                    .NewObj(propertyInterceptionInfo.Ctor,
                                                            member.Property.Getter,
                                                            member.Property.Setter,
                                                            member.Property.Name,
                                                            member.Property.ReturnType,
                                                            Crumb.This,
                                                            member.Property.ReturnType.IsArray || member.Property.ReturnType.Implements(typeof(IEnumerable)) ? member.Property.ReturnType.ChildType : null,
                                                            propertySetter == null ? null : y.NewCode().NewObj(actionObjectCtor, propertySetter)));
            })
            .Try(x =>
            {
                if (member.Property.BackingField == null)
                {
                    var oldvalue = member.Property.Getter == null ? null : x.CreateVariable(member.Property.ReturnType);

                    if (oldvalue != null)
                    {
                        var getter = member.Property.Getter.Copy();
                        x.Call(getter.IsStatic ? null : Crumb.This, getter).StoreLocal(oldvalue);
                    }

                    for (int i = 0; i < legalSetterInterceptors.Length; i++)
                    {
                        var item  = legalSetterInterceptors[i];
                        var field = interceptorFields[item.Attribute.Identification];
                        x.Load(field).As(legalSetterInterceptors[i].InterfaceSetter.ToBuilderType).Call(item.InterfaceSetter.OnSet, propertyField, oldvalue, Crumb.GetParameter(0));

                        x.IsFalse().Then(y => y.OriginalBodyNewMethod());
                    }
                }
                else
                {
                    for (int i = 0; i < legalSetterInterceptors.Length; i++)
                    {
                        var item  = legalSetterInterceptors[i];
                        var field = interceptorFields[item.Attribute.Identification];
                        x.Load(field).As(legalSetterInterceptors[i].InterfaceSetter.ToBuilderType).Call(item.InterfaceSetter.OnSet, propertyField, member.Property.BackingField, Crumb.GetParameter(0));

                        x.IsFalse().Then(y => y.OriginalBody());
                    }
                }
            })
            .Catch(typeof(Exception), x =>
            {
                for (int i = 0; i < legalSetterInterceptors.Length; i++)
                {
                    var item  = legalSetterInterceptors[i];
                    var field = interceptorFields[item.Attribute.Identification];
                    x.Load(field).As(legalSetterInterceptors[i].InterfaceSetter.ToBuilderType).Call(legalSetterInterceptors[i].InterfaceSetter.OnException, x.Exception);
                }

                x.Rethrow();
            })
            .Finally(x =>
            {
                for (int i = 0; i < legalSetterInterceptors.Length; i++)
                {
                    var item  = legalSetterInterceptors[i];
                    var field = interceptorFields[item.Attribute.Identification];
                    x.Load(field).As(legalSetterInterceptors[i].InterfaceSetter.ToBuilderType).Call(legalSetterInterceptors[i].InterfaceSetter.OnExit);
                }
            })
            .EndTry()
            .Return()
            .Replace();
        }
        private static void AddPropertyInitializeInterception(Builder builder, __PropertyInterceptionInfo propertyInterceptionInfo, PropertyBuilderInfo member, Field propertyField, Method actionObjectCtor, Method propertySetter, Dictionary <string, Field> interceptorFields)
        {
            var declaringType         = member.Property.OriginType;
            var syncRoot              = new __ISyncRoot();
            var legalInitInterceptors = member.InterceptorInfos.Where(x => x.InterfaceInitializer != null).ToArray();
            var relevantCtors         = member.Property.IsStatic ? new Method[] { declaringType.StaticConstructor } : declaringType.GetRelevantConstructors().Where(x => x.Name != ".cctor");

            foreach (var ctor in relevantCtors)
            {
                ctor.NewCode()
                .Context(x =>
                {
                    for (int i = 0; i < legalInitInterceptors.Length; i++)
                    {
                        var item  = legalInitInterceptors[i];
                        var field = interceptorFields[item.Attribute.Identification];

                        x.Assign(field).NewObj(item.Attribute);
                        if (item.HasSyncRootInterface)
                        {
                            x.Load(field).As(__ISyncRoot.Type.Import()).Call(syncRoot.SyncRoot, member.SyncRoot);
                        }

                        ImplementAssignMethodAttribute(builder, legalInitInterceptors[i].AssignMethodAttributeInfos, field, x, false);
                    }

                    x.Assign(propertyField)
                    .NewObj(propertyInterceptionInfo.Ctor,
                            member.Property.Getter,
                            member.Property.Setter,
                            member.Property.Name,
                            member.Property.ReturnType,
                            Crumb.This,
                            member.Property.ReturnType.IsArray || member.Property.ReturnType.Implements(typeof(IEnumerable)) ? member.Property.ReturnType.ChildType : null,
                            propertySetter == null ? null : x.NewCode().NewObj(actionObjectCtor, propertySetter));

                    for (int i = 0; i < legalInitInterceptors.Length; i++)
                    {
                        var item  = legalInitInterceptors[i];
                        var field = interceptorFields[item.Attribute.Identification];
                        x.Call(field, item.InterfaceInitializer.OnInitialize, propertyField, member.Property.BackingField);
                    }
                })
                .Insert(InsertionPosition.Beginning);
            }
        }