public bool TryGetPropertyInitializer <TProperty>(PropertyInfo propertyInfo, out IPropertyInitializer <TMessage, TInput> initializer)
        {
            var propertyName = propertyInfo?.Name ?? throw new ArgumentNullException(nameof(propertyInfo));

            if (_inputProperties.TryGetValue(propertyName, out var inputPropertyInfo))
            {
                var propertyType      = typeof(TProperty);
                var inputPropertyType = inputPropertyInfo.PropertyType;

                // exactly the same type, we just copy it over unmodified
                if (inputPropertyType == propertyType)
                {
                    initializer = new CopyPropertyInitializer <TMessage, TInput, TProperty>(propertyInfo, inputPropertyInfo);
                    return(true);
                }

                // can only copy to object, no idea what the destination type would/could be
                if (propertyType == typeof(object))
                {
                    var type = typeof(CopyObjectPropertyInitializer <, ,>).MakeGenericType(typeof(TMessage), typeof(TInput), inputPropertyType);
                    initializer = (IPropertyInitializer <TMessage, TInput>)Activator.CreateInstance(type, propertyInfo, inputPropertyInfo);
                    return(true);
                }

                if (_providerFactory.TryGetPropertyProvider(inputPropertyInfo, out IPropertyProvider <TInput, TProperty> provider))
                {
                    initializer = new ProviderPropertyInitializer <TMessage, TInput, TProperty>(provider, propertyInfo);
                    return(true);
                }
            }

            initializer = null;
            return(false);
        }