public override void Read(ExtendedBinaryReader reader)
 {
     for (var index = 0; index < SynchronizableTargetMembers.Length; index++)
     {
         SynchronizableTargetMember synchronizableTargetMember = SynchronizableTargetMembers[index];
         synchronizableTargetMember.ReadChanges(reader);
     }
 }
 public bool TryGetMemberByName(string memberName, out SynchronizableTargetMember synchronizableTargetMember)
 {
     for (var i = 0; i < SynchronizableTargetMembers.Length; i++)
     {
         SynchronizableTargetMember x = SynchronizableTargetMembers[i];
         if (x.Name == memberName)
         {
             synchronizableTargetMember = x;
             return(true);
         }
     }
     synchronizableTargetMember = default;
     return(false);
 }
        public ObjectTargetSynchronizer(TargetSynchronizerRoot targetSynchronizerRoot, int referenceId, Type referenceType) : base(referenceId)
        {
            _targetSynchronizerRoot = targetSynchronizerRoot;
            Reference = FormatterServices.GetUninitializedObject(referenceType);

            SynchronizableMember[] synchronizableMembers = targetSynchronizerRoot.SynchronizableMemberFactory.FromType(referenceType);

            SynchronizableTargetMembers = new SynchronizableTargetMember[synchronizableMembers.Length];
            for (var syncPropertyIndex = 0; syncPropertyIndex < synchronizableMembers.Length; syncPropertyIndex++)
            {
                SynchronizableMember synchronizableMember = synchronizableMembers[syncPropertyIndex];
                var synchronizableTargetMember            = new SynchronizableTargetMember(Reference, synchronizableMember, _targetSynchronizerRoot);
                SynchronizableTargetMembers[syncPropertyIndex] = synchronizableTargetMember;
            }
            _targetSynchronizerRoot.EndRead += TargetSynchronizerRootOnEndRead;
        }
        private void ConstructMemberConstructorParameters(SynchronizableTargetMember synchronizableTargetMember, List <object> constructionPath)
        {
            object synchronizedValue = synchronizableTargetMember.SynchronizedValue;

            if (synchronizedValue != null)
            {
                Type type = synchronizedValue.GetType();
                if (type.IsValueType == false)
                {
                    TargetSynchronizer target = _targetSynchronizerRoot.ReferencePool.GetSynchronizer(synchronizedValue);
                    if (target is ObjectTargetSynchronizer notifyPropertyChangedSyncTarget)
                    {
                        notifyPropertyChangedSyncTarget.Construct(constructionPath);
                    }
                }
            }
        }
        private void Construct(List <object> path)
        {
            path.Add(Reference);

            if (_state == State.Uninitialized)
            {
                _state = State.Constructing;
                ConstructorInfo constructor = ResolveConstructor(Reference.GetType());
                ParameterInfo[] constructorParametersInfos = constructor.GetParameters();
                object[]        constructorParameters;
                if (constructorParametersInfos.Length > 0)
                {
                    constructorParameters = new object[constructorParametersInfos.Length];
                    var synchronizableConstructorParameters = new HashSet <SynchronizableTargetMember>();

                    for (var i = 0; i < constructorParametersInfos.Length; i++)
                    {
                        ParameterInfo constructorParametersInfo = constructorParametersInfos[i];

                        object ResolveParameterValue()
                        {
                            foreach (Attribute customAttribute in constructorParametersInfo.GetCustomAttributes())
                            {
                                // Resolve property parameter explicit with attribute
                                if (customAttribute is SynchronizationParameterAttribute constructorParameterAttribute)
                                {
                                    if (TryGetMemberByName(constructorParameterAttribute.PropertyName, out SynchronizableTargetMember explicitSyncTargetProperty))
                                    {
                                        synchronizableConstructorParameters.Add(explicitSyncTargetProperty);
                                        return(explicitSyncTargetProperty.SynchronizedValue);
                                    }
                                    throw new SyncTargetMemberNotFoundException(constructorParameterAttribute.PropertyName);
                                }
                                // Resolve dependency parameter explicit with attribute
                                if (customAttribute is SynchronizationDependencyAttribute)
                                {
                                    return(_targetSynchronizerRoot.ServiceProvider.GetService(constructorParametersInfo.ParameterType) ?? throw new ArgumentNullException($"{constructor.Name}:{constructorParametersInfo.Name}"));
                                }
                            }
                            // Resolve property implicit
                            var genericMemberName = ToGenericMemberName(constructorParametersInfo.Name);

                            SynchronizableTargetMember implicitSyncTargetProperty = SynchronizableTargetMembers
                                                                                    .FirstOrDefault(targetMember => genericMemberName == ToGenericMemberName(targetMember.Name));

                            if (implicitSyncTargetProperty != null)
                            {
                                synchronizableConstructorParameters.Add(implicitSyncTargetProperty);
                                return(implicitSyncTargetProperty.SynchronizedValue);
                            }
                            //  Resolve dependency implicit
                            return(_targetSynchronizerRoot.ServiceProvider.GetService(constructorParametersInfo.ParameterType) ?? throw new ArgumentNullException($"{constructor.Name}:{constructorParametersInfo.Name}"));
                        }

                        constructorParameters[i] = ResolveParameterValue();
                    }

                    // Make sure members are initialized before invoking constructor
                    foreach (SynchronizableTargetMember syncTargetProperty in synchronizableConstructorParameters)
                    {
                        ConstructMemberConstructorParameters(syncTargetProperty, path);
                    }
                }
                else
                {
                    constructorParameters = null;
                }
                constructor.Invoke(Reference, constructorParameters);

                for (var index = 0; index < SynchronizableTargetMembers.Length; index++)
                {
                    SynchronizableTargetMember synchronizableTargetMember = SynchronizableTargetMembers[index];
                    synchronizableTargetMember.SynchronizationBehaviour = synchronizableTargetMember.DefaultSynchronizationBehaviour;

                    if (synchronizableTargetMember.SynchronizationBehaviour != SynchronizationBehaviour.Manual &&
                        synchronizableTargetMember.SynchronizationBehaviour != SynchronizationBehaviour.Construction)
                    {
                        synchronizableTargetMember.Value = synchronizableTargetMember.SynchronizedValue;
                    }
                }

                _state = State.Constructed;

                if (_constructionCallbacks != null)
                {
                    foreach (Action <object> constructionCallback in _constructionCallbacks)
                    {
                        constructionCallback.Invoke(Reference);
                    }
                    _constructionCallbacks = null;
                }
            }
            else if (_state == State.Constructing)
            {
                throw new ConstructorReferenceCycleException(path);
            }
        }