public override void Apply(DynamicTypeBuilder typeBuilder)
        {
            var properties = from p in typeBuilder.BaseType.GetProperties()
                             let set = p.GetSetMethod(true)
                                       where set != null && (set.IsPublic || set.IsFamily)
                                       select p;

            if (NotifyPropertyChanged)
            {
                foreach (var item in properties)
                {
                    typeBuilder.AddMember(new DynamicProperty(item.Name, item.PropertyType));
                }
            }

            this.TransactionProxyProperties = new Collection <TransactionProxyProperty>();

            foreach (var item in properties)
            {
                var tpp = new TransactionProxyProperty {
                    Property = item
                };
                tpp.HasMultipleValuesProperty = new DynamicProperty(
                    string.Format("{0}_HasMultipleValues", item.Name),
                    typeof(bool),
                    false);

                tpp.ValuesProperty = new DynamicProperty(
                    string.Format("{0}_Values", item.Name),
                    typeof(Dictionary <,>).MakeGenericType(typeof(Key <>).MakeGenericType(item.PropertyType), typeof(List <>).MakeGenericType(typeBuilder.BaseType)),
                    true);
                typeBuilder.AddMember(tpp.HasMultipleValuesProperty);
                typeBuilder.AddMember(tpp.ValuesProperty);
                this.TransactionProxyProperties.Add(tpp);
            }

            this.TargetsField = new DynamicField(Guid.NewGuid().ToString(), typeof(List <>).MakeGenericType(typeBuilder.BaseType));
            typeBuilder.AddMember(this.TargetsField);

            this.CommitMethod = new CommitMethod();
            typeBuilder.AddMember(this.CommitMethod);
            this.RollbackMethod = new RollbackMethod();
            typeBuilder.AddMember(this.RollbackMethod);
            this.GetTransactionProxyTargetsMethod = new Methods.GetTransactionProxyTargetsMethod();
            typeBuilder.AddMember(this.GetTransactionProxyTargetsMethod);
            this.GetTransactionProxyTypedTargetsMethod = new Methods.GetTransactionProxyTypedTargetsMethod(typeBuilder.BaseType);
            typeBuilder.AddMember(this.GetTransactionProxyTypedTargetsMethod);
            this.SetTransactionProxyTargetsMethod = new Methods.SetTransactionProxyTargetsMethod();
            typeBuilder.AddMember(this.SetTransactionProxyTargetsMethod);
            this.SetTransactionProxyTypedTargetsMethod = new Methods.SetTransactionProxyTypedTargetsMethod(typeBuilder.BaseType);
            typeBuilder.AddMember(this.SetTransactionProxyTypedTargetsMethod);

            typeBuilder.AddInterceptor(new ImplementInterfaceInterceptor <ICommitable>());
            typeBuilder.AddInterceptor(new ImplementInterfaceInterceptor <ITransactionProxy>());
            typeBuilder.AddInterceptor(new ImplementInterfaceInterceptor(typeof(ITransactionProxy <>).MakeGenericType(typeBuilder.BaseType)));
        }
        public override void Apply(DynamicTypeBuilder typeBuilder)
        {
            var properties = from p in ItemType.GetProperties()
                             let set = p.GetSetMethod(true)
                                       where set != null && (set.IsPublic || set.IsFamily)
                                       select p;

            this.TransactionProxyProperties = new Collection <TransactionProxyProperty>();

            var baseTypeNotifications = !ItemType.IsInterface && ItemType.GetInterfaces().Contains(typeof(INotifyPropertyChanged));

            foreach (var item in properties)
            {
                DynamicProperty baseProp = null;

                if (IsInterface)
                {
                    baseProp = new DynamicInterfaceProperty(item.Name, item.PropertyType);
                }
                else
                {
                    baseProp = new DynamicProperty(item.Name, item.PropertyType);
                }

                var tpp = new TransactionProxyProperty {
                    Property = item, DynamicProperty = baseProp
                };

                tpp.HasMultipleValuesProperty = new DynamicProperty(
                    $"{item.Name}_HasMultipleValues",
                    typeof(bool),
                    false);

                tpp.ValuesProperty = new DynamicProperty(
                    $"{item.Name}_Values",
                    typeof(Dictionary <,>).MakeGenericType(typeof(Key <>).MakeGenericType(item.PropertyType), typeof(List <>).MakeGenericType(ItemType)),
                    true);

                typeBuilder.AddMember(baseProp);
                typeBuilder.AddMember(tpp.HasMultipleValuesProperty);
                typeBuilder.AddMember(tpp.ValuesProperty);

                if (NotifyPropertyChanged)
                {
                    tpp.DynamicProperty.AddSetInterceptor(new ResetHasMultipleValuesInterceptor());
                }

                this.TransactionProxyProperties.Add(tpp);
            }

            this.TargetsField = new DynamicField(Guid.NewGuid().ToString(), typeof(List <>).MakeGenericType(ItemType));
            typeBuilder.AddMember(this.TargetsField);

            this.CommitMethod = new CommitMethod();
            typeBuilder.AddMember(this.CommitMethod);
            this.RollbackMethod = new RollbackMethod();
            typeBuilder.AddMember(this.RollbackMethod);
            this.GetTransactionProxyTargetsMethod = new Methods.GetTransactionProxyTargetsMethod();
            typeBuilder.AddMember(this.GetTransactionProxyTargetsMethod);
            this.GetTransactionProxyTypedTargetsMethod = new Methods.GetTransactionProxyTypedTargetsMethod(ItemType);
            typeBuilder.AddMember(this.GetTransactionProxyTypedTargetsMethod);
            this.SetTransactionProxyTargetsMethod = new Methods.SetTransactionProxyTargetsMethod();
            typeBuilder.AddMember(this.SetTransactionProxyTargetsMethod);
            this.SetTransactionProxyTypedTargetsMethod = new Methods.SetTransactionProxyTypedTargetsMethod(ItemType);
            typeBuilder.AddMember(this.SetTransactionProxyTypedTargetsMethod);

            this.GetValueEntiresMethod = new Methods.GetValueEntriesMethod();
            typeBuilder.AddMember(this.GetValueEntiresMethod);

            this.GetValueEntiresTypedMethod = new Methods.GetValueEntriesTypedMethod(ItemType);
            typeBuilder.AddMember(this.GetValueEntiresTypedMethod);

            this.HasMultipleValuesMethod = new Methods.HasMultipleValuesMethod();
            typeBuilder.AddMember(this.HasMultipleValuesMethod);

            typeBuilder.AddInterceptor(new ImplementInterfaceInterceptor <ICommitable>());
            typeBuilder.AddInterceptor(new ImplementInterfaceInterceptor <ITransactionProxy>());
            typeBuilder.AddInterceptor(new ImplementInterfaceInterceptor(typeof(ITransactionProxy <>).MakeGenericType(ItemType)));
        }