public void RegisterSubclass(Type type)
        {
            var typeInfo = type.GetTypeInfo();

            if (!typeof(ParseObject).GetTypeInfo().IsAssignableFrom(typeInfo))
            {
                throw new ArgumentException("Cannot register a type that is not a subclass of ParseObject");
            }

            var className = GetClassName(type);

            try
            {
                // Perform this as a single independent transaction, so we can never get into an
                // intermediate state where we *theoretically* register the wrong class due to a
                // TOCTTOU bug.
                _mutex.EnterWriteLock();

                if (_registeredSubclasses.TryGetValue(className, out var previousInfo))
                {
                    if (typeInfo.IsAssignableFrom(previousInfo.TypeInfo))
                    {
                        // Previous subclass is more specific or equal to the current type, do nothing.
                        return;
                    }
                    else if (previousInfo.TypeInfo.IsAssignableFrom(typeInfo))
                    {
                        // Previous subclass is parent of new child, fallthrough and actually register
                        // this class.
                        /* Do nothing */
                    }
                    else
                    {
                        throw new ArgumentException(
                                  "Tried to register both " + previousInfo.TypeInfo.FullName + " and " + typeInfo.FullName +
                                  " as the ParseObject subclass of " + className + ". Cannot determine the right class " +
                                  "to use because neither inherits from the other."
                                  );
                    }
                }

                ConstructorInfo constructor = type.FindConstructor();
                if (constructor == null)
                {
                    throw new ArgumentException(
                              "Cannot register a type that does not implement the default constructor!");
                }

                _registeredSubclasses[className] = new ObjectSubclassInfo(type, constructor);
            }
            finally
            {
                _mutex.ExitWriteLock();
            }

            _mutex.EnterReadLock();
            _registerActions.TryGetValue(className, out var toPerform);
            _mutex.ExitReadLock();

            toPerform?.Invoke();
        }
 public string GetClassName(Type type)
 {
     return(type == typeof(ParseObject)
         ? ParseObjectClassName
         : ObjectSubclassInfo.GetClassName(type.GetTypeInfo()));
 }