Пример #1
0
        /// <summary>
        /// Gets accessors for all the objects specified. This method is relatively thread-safe and null-safe. Multiple threads trying to access the same accessors using this method
        /// are unlikely to make each other deadlock. Deadlock can still occur if one thread forgets to dispose of an accessor, or hogs it to itself. Softlocking can still occur if
        /// the calls are tailored to do their best to interfere with each other, but deadlocking is impossible when using this method and accessors are disposed of properly
        /// </summary>
        /// <param name="objects">The set of objects to generate accessors for</param>
        /// <returns>An array of accessors. Duplicate and linked accessors can exist if duplicate or linked objects are in the array.</returns>
        public static async Task <IAccessor[]> GetAccessors(params TSObject[] objects)
        {
            if (objects == null)
            {
                return(null);
            }

            IAccessor[] accessors = new IAccessor[objects.Length];
            Dictionary <TSObject, IAccessor> mapping = new Dictionary <TSObject, IAccessor>();
            HashSet <IAccessor> owned = new HashSet <IAccessor>();

            try
            {
                bool restart;
                do
                {
                    restart = false;
                    foreach (TSObject obj in objects.Distinct()) // Loop through all objects
                    {
                        if (obj == null)                         // We don't care if it's null, it can just be null
                        {
                            continue;
                        }

                        if (mapping.ContainsKey(obj)) // We also don't care if we've done it already
                        {
                            continue;
                        }

                        IAccessor a;

                        if (await obj.Sync.Execute(() =>
                        {
                            if (owned.Contains(obj.Owner))
                            {
                                mapping[obj] = new ProxyAccessor(obj, obj.Owner);
                                return(true);
                            }
                            return(false);
                        }))
                        {
                            continue;
                        }

                        a = await obj.CreateAccessor(100).ConfigureAwait(false); // Try to get the accessor, timeout after a 1/10th of a seccond

                        if (a == null)                                           // If we couldn't get an accessor quickly, then release all our accessors, and wait for this one. This is to prevent deadlocks
                        {
                            foreach (IAccessor access in mapping.Values)         // Dispose of all our current accessors
                            {
                                access.Dispose();
                            }
                            mapping.Clear();                                      // Clear them away, they're not valid anymore
                            owned.Clear();                                        // Clear away the owned accessors too

                            a = await obj.CreateAccessor().ConfigureAwait(false); // Wait for the accessor

                            mapping[obj] = a;                                     // Map it
                            owned.Add(a);                                         // Add it to the list of owned accessors

                            restart = true;                                       // Flag the program to retry after
                            break;                                                // End current cycle of attempts so we can have a fresh start again
                        }
                        mapping[obj] = a;                                         // We got the accessor, so add it to our map
                        owned.Add(a);                                             // and also add it to the list of owned accessors for linkage detection
                    }
                }while (restart);

                for (int i = 0; i < accessors.Length; i++) // For each accessor requested, if its not null, assign the accessor we got to it.
                {
                    if (objects[i] != null)
                    {
                        accessors[i] = mapping[objects[i]];
                    }
                }
            }
            catch
            {
                foreach (Accessor a in mapping.Values) // Dispose of all the accessors, so we don't leave them in an unusable state
                {
                    a.Dispose();
                }
                throw;
            }
            return(accessors); // Return our array of accessors. If there were duplicate objects, then there will be duplicate accessors, same with null objects and null accessors
        }
Пример #2
0
        protected void Wire(IOgmConnection connection)
        {
            if (connection != null)
            {
                using (ManagerAccess.Manager.ScopeOMnG())
                {
                    if (IsInverse)
                    {
                        if (Context.TypesManager.IsGraphEntityCollection(DestinationProperty.PropertyType))
                        {
                            object coll = ObjectExtensions.Configuration.Get(DestinationProperty, connection.Destination);
                            coll.GetType().GetMethod(nameof(ICollection <int> .Add)).Invoke(coll, new[] { connection is OgmConnection ? connection.Destination : connection });
                        }
                        else
                        {
                            ObjectExtensions.Configuration.Set(DestinationProperty, ProxyAccessor.DynProxyGetTarget(), connection is OgmConnection ? connection.Destination : connection);
                        }

                        if (SourceProperty != null)
                        {
                            if (Context.TypesManager.IsGraphEntityCollection(SourceProperty.PropertyType))
                            {
                                object coll = ObjectExtensions.Configuration.Get(SourceProperty, connection.Source);
                                if (coll == null)
                                {
                                    if (SourceProperty.CanWrite)
                                    {
                                        coll = Activator.CreateInstance(SourceProperty.PropertyType);
                                        ObjectExtensions.Configuration.Set(SourceProperty, connection.Source, coll);
                                    }
                                    else
                                    {
                                        throw new InvalidOperationException($"Unable to set property {SourceProperty.ReflectedType.FullName}.{SourceProperty.Name}");
                                    }
                                }
                                coll.GetType().GetMethod(nameof(ICollection <int> .Add)).Invoke(coll, new[] { connection.Destination });
                            }
                            else
                            {
                                ObjectExtensions.Configuration.Set(SourceProperty, connection.Source, connection.Destination);
                            }
                        }
                    }
                    else
                    {
                        if (Context.TypesManager.IsGraphEntityCollection(SourceProperty.PropertyType))
                        {
                            object coll = ObjectExtensions.Configuration.Get(SourceProperty, connection.Source);
                            coll.GetType().GetMethod(nameof(ICollection <int> .Add)).Invoke(coll, new[] { connection is OgmConnection ? connection.Destination : connection });
                        }
                        else
                        {
                            ObjectExtensions.Configuration.Set(SourceProperty, ProxyAccessor.DynProxyGetTarget(), connection is OgmConnection ? connection.Destination : connection);
                        }

                        if (DestinationProperty != null)
                        {
                            if (Context.TypesManager.IsGraphEntityCollection(DestinationProperty.PropertyType))
                            {
                                object coll = ObjectExtensions.Configuration.Get(DestinationProperty, connection.Destination);
                                if (coll == null)
                                {
                                    if (DestinationProperty.CanWrite)
                                    {
                                        coll = Activator.CreateInstance(DestinationProperty.PropertyType);
                                        ObjectExtensions.Configuration.Set(DestinationProperty, connection.Destination, coll);
                                    }
                                    else
                                    {
                                        throw new InvalidOperationException($"Unable to set property {DestinationProperty.ReflectedType.FullName}.{DestinationProperty.Name}");
                                    }
                                }
                                coll.GetType().GetMethod(nameof(ICollection <int> .Add)).Invoke(coll, new[] { connection.Source });
                            }
                            else
                            {
                                ObjectExtensions.Configuration.Set(DestinationProperty, connection.Destination, connection.Source);
                            }
                        }
                    }
                }
            }
        }