Exemple #1
0
        public Task <IBinding> TryCreateAsync(BindingProviderContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            ParameterInfo parameter       = context.Parameter;
            TAttribute    attributeSource = parameter.GetCustomAttribute <TAttribute>(inherit: false);

            if (attributeSource == null)
            {
                return(Task.FromResult <IBinding>(null));
            }

            var cloner = new AttributeCloner <TAttribute>(attributeSource, context.BindingDataContract, _nameResolver);

            IBinding binding = new Binding(cloner, _builder, parameter);

            return(Task.FromResult(binding));
        }
        public Task <IBinding> TryCreateAsync(BindingProviderContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }
            Type parametertype = context.Parameter.ParameterType;

            var attr = context.Parameter.GetCustomAttribute <TAttribute>();

            var cloner           = new AttributeCloner <TAttribute>(attr, context.BindingDataContract, _nameResolver);
            var attrNameResolved = cloner.GetNameResolvedAttribute();

            // This may do validation and throw too.
            bool canBind = _predicate(attrNameResolved, parametertype);

            if (!canBind)
            {
                return(Task.FromResult <IBinding>(null));
            }
            return(_inner.TryCreateAsync(context));
        }
Exemple #3
0
        public async Task <IBinding> TryCreateAsync(BindingProviderContext context)
        {
            var attr = context.Parameter.GetCustomAttribute <TAttribute>();

            if (attr == null)
            {
                return(null);
            }

            if (_validator != null)
            {
                // Expected this will throw on errors.
                Type parameterType    = context.Parameter.ParameterType;
                var  cloner           = new AttributeCloner <TAttribute>(attr, context.BindingDataContract, _nameResolver);
                var  attrNameResolved = cloner.GetNameResolvedAttribute();
                _validator(attrNameResolved, parameterType);
            }

            foreach (IBindingProvider provider in _providers)
            {
                IBinding binding = await provider.TryCreateAsync(context);

                if (binding != null)
                {
                    return(binding);
                }
            }

            // Nobody claimed it.
            string       resourceName = typeof(TAttribute).Name;
            const string Suffix       = "Attribute";

            if (resourceName.EndsWith(Suffix))
            {
                resourceName = resourceName.Substring(0, resourceName.Length - Suffix.Length);
            }
            throw new InvalidOperationException("Can't bind " + resourceName + " to type '" + context.Parameter.ParameterType + "'.");
        }
        private static Func <TAttribute, IValueProvider> BuildIAsyncCollectorArgument <TAttribute, TMessage, TMessageSrc>(
            IConverterManager cm,
            Func <TAttribute, IAsyncCollector <TMessage> > buildFromAttribute,
            AttributeCloner <TAttribute> cloner)
            where TAttribute : Attribute
        {
            Func <TMessageSrc, TAttribute, TMessage> convert = cm.GetConverter <TMessageSrc, TMessage, TAttribute>();

            if (convert == null)
            {
                ThrowMissingConversionError(typeof(TMessageSrc));
            }
            Func <TAttribute, IValueProvider> argumentBuilder = (attrResolved) =>
            {
                IAsyncCollector <TMessage>    raw = buildFromAttribute(attrResolved);
                IAsyncCollector <TMessageSrc> obj = new TypedAsyncCollectorAdapter <TMessageSrc, TMessage, TAttribute>(
                    raw, convert, attrResolved);
                var invokeString = cloner.GetInvokeString(attrResolved);
                return(new AsyncCollectorValueProvider <IAsyncCollector <TMessageSrc>, TMessage>(obj, raw, invokeString));
            };

            return(argumentBuilder);
        }
Exemple #5
0
        public async Task <IBinding> TryCreateAsync(BindingProviderContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            var binding = await _inner.TryCreateAsync(context);

            if (binding != null)
            {
                // Only run the validator if the inner binding claims it.
                // Expected this will throw on errors.
                Type parameterType = context.Parameter.ParameterType;
                var  attr          = context.Parameter.GetCustomAttribute <TAttribute>();

                var cloner           = new AttributeCloner <TAttribute>(attr, context.BindingDataContract, _configuration, _nameResolver);
                var attrNameResolved = cloner.GetNameResolvedAttribute();
                _validator(attrNameResolved, parameterType);
            }

            return(binding);
        }
Exemple #6
0
        public static TAttribute FromInvokeString(AttributeCloner <TAttribute> cloner, string invokeString)
        {
            if (invokeString == null)
            {
                throw new ArgumentNullException(nameof(invokeString));
            }

            // Instantiating new attributes can be tricky since sometimes the arg is to the ctor and sometimes
            // its a property setter. AttributeCloner already solves this, so use it here to do the actual attribute instantiation.
            // This has an instantiation problem similar to what Attribute Cloner has
            if (invokeString[0] == '{')
            {
                var propertyValues = JsonConvert.DeserializeObject <IDictionary <string, string> >(invokeString);

                var attr = cloner.New(propertyValues);
                return(attr);
            }
            else
            {
                var attr = cloner.New(invokeString);
                return(attr);
            }
        }
        private static Func <TAttribute, IValueProvider> BuildOutArgument <TAttribute, TMessage, TMessageSrc>(
            IConverterManager cm,
            Func <TAttribute, IAsyncCollector <TMessage> > buildFromAttribute,
            AttributeCloner <TAttribute> cloner)
            where TAttribute : Attribute
        {
            // Other
            Func <TMessageSrc, TAttribute, TMessage> convert = cm.GetConverter <TMessageSrc, TMessage, TAttribute>();

            if (convert == null)
            {
                return(null);
            }
            Func <TAttribute, IValueProvider> argumentBuilder = (attrResolved) =>
            {
                IAsyncCollector <TMessage>    raw = buildFromAttribute(attrResolved);
                IAsyncCollector <TMessageSrc> obj = new TypedAsyncCollectorAdapter <TMessageSrc, TMessage, TAttribute>(
                    raw, convert, attrResolved);
                string invokeString = cloner.GetInvokeString(attrResolved);
                return(new OutValueProvider <TMessageSrc>(obj, invokeString));
            };

            return(argumentBuilder);
        }
Exemple #8
0
 public BindingBase(AttributeCloner <TAttribute> cloner, ParameterDescriptor param)
 {
     Cloner = cloner;
     _param = param;
 }
        // Helper to bind an IAsyncCollector<TMessage> to an 'out TUser' pattern, and invoke converter manager as needed.
        private static Func <TAttribute, IValueProvider> BindAsyncCollectorToOut <TAttribute, TMessage>(
            ParameterInfo parameter,
            IConverterManager converterManager,
            Func <TAttribute, IAsyncCollector <TMessage> > buildFromAttribute,
            AttributeCloner <TAttribute> cloner)
            where TAttribute : Attribute
        {
            Func <TAttribute, IValueProvider> argumentBuilder;
            Type elementType = parameter.ParameterType.GetElementType();

            // How should "out byte[]" bind?
            // If there's an explicit "byte[] --> TMessage" converter, then that takes precedence.
            // Else, bind over an array of "byte --> TMessage" converters

            argumentBuilder = DynamicInvokeBuildOutArgument(elementType, converterManager, buildFromAttribute, cloner);

            if (argumentBuilder != null)
            {
            }
            else if (elementType.IsArray)
            {
                if (elementType == typeof(TMessage[]))
                {
                    argumentBuilder = (attrResolved) =>
                    {
                        IAsyncCollector <TMessage> raw = buildFromAttribute(attrResolved);
                        var invokeString = cloner.GetInvokeString(attrResolved);
                        return(new OutArrayValueProvider <TMessage>(raw, invokeString));
                    };
                }
                else
                {
                    // out TMessage[]
                    var e2 = elementType.GetElementType();
                    argumentBuilder = DynamicBuildOutArrayArgument(e2, converterManager, buildFromAttribute, cloner);
                }
            }
            else
            {
                // Single enqueue
                //    out TMessage
                if (elementType == typeof(TMessage))
                {
                    argumentBuilder = (attrResolved) =>
                    {
                        IAsyncCollector <TMessage> raw = buildFromAttribute(attrResolved);
                        var invokeString = cloner.GetInvokeString(attrResolved);
                        return(new OutValueProvider <TMessage>(raw, invokeString));
                    };
                }
            }

            // For out-param, give some rich errors.
            if (argumentBuilder == null)
            {
                if (typeof(IEnumerable).IsAssignableFrom(elementType))
                {
                    throw new InvalidOperationException(
                              "Enumerable types are not supported. Use ICollector<T> or IAsyncCollector<T> instead.");
                }
                else if (typeof(object) == elementType)
                {
                    throw new InvalidOperationException("Object element types are not supported.");
                }
            }

            return(argumentBuilder);
        }
        // Helper to bind an IAsyncCollector<TMessage> raw object to an IAsyncCollector<TUser> or ICollecter<TUser> and invoke converter manager as needed.
        private static Func <TAttribute, IValueProvider> BindAsyncCollectorToInterface <TAttribute, TMessage>(IConverterManager converterManager, Func <TAttribute, IAsyncCollector <TMessage> > buildFromAttribute, AttributeCloner <TAttribute> cloner, Type parameterType, Func <TAttribute, IValueProvider> argumentBuilder) where TAttribute : Attribute
        {
            var genericType = parameterType.GetGenericTypeDefinition();
            var elementType = parameterType.GetGenericArguments()[0];

            if (genericType == typeof(IAsyncCollector <>))
            {
                if (elementType == typeof(TMessage))
                {
                    // Bind to IAsyncCollector<TMessage>. This is the "purest" binding, no adaption needed.
                    argumentBuilder = (attrResolved) =>
                    {
                        IAsyncCollector <TMessage> raw = buildFromAttribute(attrResolved);
                        var invokeString = cloner.GetInvokeString(attrResolved);

                        return(new AsyncCollectorValueProvider <IAsyncCollector <TMessage>, TMessage>(raw, raw, invokeString));
                    };
                }
                else
                {
                    // Bind to IAsyncCollector<T>
                    // Get a converter from T to TMessage
                    argumentBuilder = DynamicInvokeBuildIAsyncCollectorArgument(elementType, converterManager, buildFromAttribute, cloner);
                }
            }
            else if (genericType == typeof(ICollector <>))
            {
                if (elementType == typeof(TMessage))
                {
                    // Bind to ICollector<TMessage> This just needs an Sync/Async wrapper
                    argumentBuilder = (attrResolved) =>
                    {
                        IAsyncCollector <TMessage> raw = buildFromAttribute(attrResolved);
                        var invokeString          = cloner.GetInvokeString(attrResolved);
                        ICollector <TMessage> obj = new SyncAsyncCollectorAdapter <TMessage>(raw);
                        return(new AsyncCollectorValueProvider <ICollector <TMessage>, TMessage>(obj, raw, invokeString));
                    };
                }
                else
                {
                    // Bind to ICollector<T>.
                    // This needs both a conversion from T to TMessage and an Sync/Async wrapper
                    argumentBuilder = DynamicInvokeBuildICollectorArgument(elementType, converterManager, buildFromAttribute, cloner);
                }
            }

            return(argumentBuilder);
        }
        internal static IBinding BindCollector <TAttribute, TMessage>(
            ParameterInfo parameter,
            INameResolver nameResolver,
            IConverterManager converterManager,
            IReadOnlyDictionary <string, Type> bindingDataContract,
            Func <TAttribute, IAsyncCollector <TMessage> > buildFromAttribute,
            Func <TAttribute, ParameterInfo, INameResolver, ParameterDescriptor> buildParamDescriptor = null,
            Func <TAttribute, ParameterInfo, INameResolver, Task <TAttribute> > hook = null)
            where TAttribute : Attribute
        {
            if (parameter == null)
            {
                throw new ArgumentNullException("parameter");
            }

            Func <TAttribute, Task <TAttribute> > hookWrapper = null;

            if (hook != null)
            {
                hookWrapper = (attr) => hook(attr, parameter, nameResolver);
            }
            TAttribute attributeSource = parameter.GetCustomAttribute <TAttribute>(inherit: false);

            // ctor will do validation and throw.
            var cloner = new AttributeCloner <TAttribute>(attributeSource, bindingDataContract, nameResolver, hookWrapper);

            Type parameterType = parameter.ParameterType;

            Func <TAttribute, IValueProvider> argumentBuilder = null;

            // C# reflection trivia: If .IsOut = true, then IsGenericType = false.
            if (parameterType.IsGenericType)
            {
                argumentBuilder = BindAsyncCollectorToInterface(converterManager, buildFromAttribute, cloner, parameterType, argumentBuilder);
            }

            if (parameter.IsOut)
            {
                argumentBuilder = BindAsyncCollectorToOut(parameter, converterManager, buildFromAttribute, cloner);
            }

            if (argumentBuilder == null)
            {
                // Can't bind it.
                return(null);
            }

            ParameterDescriptor param;

            if (buildParamDescriptor != null)
            {
                param = buildParamDescriptor(attributeSource, parameter, nameResolver);
            }
            else
            {
                // If no parameter supplied, use a default.
                param = new ParameterDescriptor
                {
                    Name         = parameter.Name,
                    DisplayHints = new ParameterDisplayHints
                    {
                        Description = "output"
                    }
                };
            }

            return(new AsyncCollectorBinding <TAttribute, TMessage>(param, argumentBuilder, cloner));
        }
Exemple #12
0
            public static ExactBinding <TMessage> TryBuild(
                AsyncCollectorBindingProvider <TAttribute, TType> parent,
                Mode mode,
                BindingProviderContext context)
            {
                var patternMatcher = parent._patternMatcher;

                var        parameter       = context.Parameter;
                TAttribute attributeSource = parameter.GetCustomAttribute <TAttribute>(inherit: false);

                Func <TAttribute, Task <TAttribute> > hookWrapper = null;

                if (parent.PostResolveHook != null)
                {
                    hookWrapper = (attrResolved) => parent.PostResolveHook(attrResolved, parameter, parent._nameResolver);
                }

                Func <object, object> buildFromAttribute;
                FuncConverter <TMessage, TAttribute, TType> converter = null;

                // Prefer the shortest route to creating the user type.
                // If TType matches the user type directly, then we should be able to directly invoke the builder in a single step.
                //   TAttribute --> TUserType
                var checker = ConverterManager.GetTypeValidator <TType>();

                if (checker.IsMatch(typeof(TMessage)))
                {
                    buildFromAttribute = patternMatcher.TryGetConverterFunc(
                        typeof(TAttribute), typeof(IAsyncCollector <TMessage>));
                }
                else
                {
                    var converterManager = parent._converterManager;

                    // Try with a converter
                    // Find a builder for :   TAttribute --> TType
                    // and then couple with a converter:  TType --> TParameterType
                    converter = converterManager.GetConverter <TMessage, TType, TAttribute>();
                    if (converter == null)
                    {
                        // Preserves legacy behavior. This means we can only have 1 async collector.
                        // However, the collector's builder object can switch.
                        throw NewMissingConversionError(typeof(TMessage));
                    }

                    buildFromAttribute = patternMatcher.TryGetConverterFunc(
                        typeof(TAttribute), typeof(IAsyncCollector <TType>));
                }

                if (buildFromAttribute == null)
                {
                    return(null);
                }

                ParameterDescriptor param;

                if (parent.BuildParameterDescriptor != null)
                {
                    param = parent.BuildParameterDescriptor(attributeSource, parameter, parent._nameResolver);
                }
                else
                {
                    param = new ParameterDescriptor
                    {
                        Name         = parameter.Name,
                        DisplayHints = new ParameterDisplayHints
                        {
                            Description = "output"
                        }
                    };
                }

                var cloner = new AttributeCloner <TAttribute>(attributeSource, context.BindingDataContract, parent._nameResolver, hookWrapper);

                return(new ExactBinding <TMessage>(cloner, param, mode, buildFromAttribute, converter));
            }
Exemple #13
0
            public static ExactBinding <TUserType> TryBuild(
                BindToInputBindingProvider <TAttribute, TType> parent,
                BindingProviderContext context)
            {
                var cm             = parent._converterManager;
                var patternMatcher = parent._patternMatcher;

                var        parameter       = context.Parameter;
                TAttribute attributeSource = parameter.GetCustomAttribute <TAttribute>(inherit: false);

                Func <TAttribute, Task <TAttribute> > hookWrapper = null;

                if (parent.PostResolveHook != null)
                {
                    hookWrapper = (attrResolved) => parent.PostResolveHook(attrResolved, parameter, parent._nameResolver);
                }

                var cloner = new AttributeCloner <TAttribute>(attributeSource, context.BindingDataContract, parent._nameResolver, hookWrapper);

                Func <object, object> buildFromAttribute;
                FuncConverter <TType, TAttribute, TUserType> converter = null;

                // Prefer the shortest route to creating the user type.
                // If TType matches the user type directly, then we should be able to directly invoke the builder in a single step.
                //   TAttribute --> TUserType
                var checker = ConverterManager.GetTypeValidator <TType>();

                if (checker.IsMatch(typeof(TUserType)))
                {
                    buildFromAttribute = patternMatcher.TryGetConverterFunc(typeof(TAttribute), typeof(TUserType));
                }
                else
                {
                    // Try with a converter
                    // Find a builder for :   TAttribute --> TType
                    // and then couple with a converter:  TType --> TParameterType
                    converter = cm.GetConverter <TType, TUserType, TAttribute>();
                    if (converter == null)
                    {
                        return(null);
                    }

                    buildFromAttribute = patternMatcher.TryGetConverterFunc(typeof(TAttribute), typeof(TType));
                }

                if (buildFromAttribute == null)
                {
                    return(null);
                }

                ParameterDescriptor param;

                if (parent.BuildParameterDescriptor != null)
                {
                    param = parent.BuildParameterDescriptor(attributeSource, parameter, parent._nameResolver);
                }
                else
                {
                    param = new ParameterDescriptor
                    {
                        Name         = parameter.Name,
                        DisplayHints = new ParameterDisplayHints
                        {
                            Description = "input"
                        }
                    };
                }

                return(new ExactBinding <TUserType>(cloner, param, buildFromAttribute, converter));
            }
            public static ExactBinding <TMessage> TryBuild(
                AsyncCollectorBindingProvider <TAttribute, TType> parent,
                Mode mode,
                BindingProviderContext context)
            {
                var patternMatcher = parent._patternMatcher;

                var parameter       = context.Parameter;
                var attributeSource = TypeUtility.GetResolvedAttribute <TAttribute>(parameter);

                FuncAsyncConverter buildFromAttribute;
                FuncAsyncConverter <TMessage, TType> converter = null;

                // Prefer the shortest route to creating the user type.
                // If TType matches the user type directly, then we should be able to directly invoke the builder in a single step.
                //   TAttribute --> TUserType
                var checker = OpenType.FromType <TType>();

                if (checker.IsMatch(typeof(TMessage)))
                {
                    buildFromAttribute = patternMatcher.TryGetConverterFunc(
                        typeof(TAttribute), typeof(IAsyncCollector <TMessage>));
                }
                else
                {
                    var converterManager = parent._converterManager;

                    // Try with a converter
                    // Find a builder for :   TAttribute --> TType
                    // and then couple with a converter:  TType --> TParameterType
                    converter = converterManager.GetConverter <TMessage, TType, TAttribute>();
                    if (converter == null)
                    {
                        // Preserves legacy behavior. This means we can only have 1 async collector.
                        // However, the collector's builder object can switch.
                        throw NewMissingConversionError(typeof(TMessage));
                    }

                    buildFromAttribute = patternMatcher.TryGetConverterFunc(
                        typeof(TAttribute), typeof(IAsyncCollector <TType>));
                }

                if (buildFromAttribute == null)
                {
                    context.BindingErrors.Add(String.Format(Constants.BindingAssemblyConflictMessage, typeof(TType).AssemblyQualifiedName, typeof(TMessage).AssemblyQualifiedName));
                    return(null);
                }

                ParameterDescriptor param;

                if (parent.BuildParameterDescriptor != null)
                {
                    param = parent.BuildParameterDescriptor(attributeSource, parameter, parent._nameResolver);
                }
                else
                {
                    param = new ParameterDescriptor
                    {
                        Name         = parameter.Name,
                        DisplayHints = new ParameterDisplayHints
                        {
                            Description = "output"
                        }
                    };
                }

                var cloner = new AttributeCloner <TAttribute>(attributeSource, context.BindingDataContract, parent._nameResolver);

                return(new ExactBinding <TMessage>(cloner, param, mode, buildFromAttribute, converter));
            }
            public static IBinding TryBuild <TUserType>(
                BindToStreamBindingProvider <TAttribute> parent,
                BindingProviderContext context)
            {
                // Allowed Param types:
                //  Stream
                //  any T with a Stream --> T conversion
                // out T, with a Out<Stream,T> --> void conversion

                var parameter     = context.Parameter;
                var parameterType = parameter.ParameterType;


                var attributeSource = TypeUtility.GetResolvedAttribute <TAttribute>(parameter);

                // Stream is either way; all other types are known.
                FileAccess?declaredAccess = GetFileAccessFromAttribute(attributeSource);

                Type argHelperType;
                bool isRead;

                IConverterManager cm     = parent._converterManager;
                INameResolver     nm     = parent._nameResolver;
                IConfiguration    config = parent._configuration;

                object converterParam = null;

                {
                    if (parameter.IsOut)
                    {
                        var outConverter = cm.GetConverter <ApplyConversion <TUserType, Stream>, object, TAttribute>();
                        if (outConverter != null)
                        {
                            converterParam = outConverter;
                            isRead         = false;
                            argHelperType  = typeof(OutArgBaseValueProvider <>).MakeGenericType(typeof(TAttribute), typeof(TUserType));
                        }
                        else
                        {
                            throw new InvalidOperationException($"No stream converter to handle {typeof(TUserType).FullName}.");
                        }
                    }
                    else
                    {
                        var converter = cm.GetConverter <Stream, TUserType, TAttribute>();
                        if (converter != null)
                        {
                            converterParam = converter;

                            if (parameterType == typeof(Stream))
                            {
                                if (!declaredAccess.HasValue)
                                {
                                    throw new InvalidOperationException("When binding to Stream, the attribute must specify a FileAccess direction.");
                                }
                                switch (declaredAccess.Value)
                                {
                                case FileAccess.Read:
                                    isRead = true;

                                    break;

                                case FileAccess.Write:
                                    isRead = false;
                                    break;

                                default:
                                    throw new NotImplementedException("ReadWrite access is not supported. Pick either Read or Write.");
                                }
                            }
                            else
                            {
                                // For backwards compat, we recognize TextWriter as write;
                                // anything else should explicitly set the FileAccess flag.
                                if (typeof(TextWriter).IsAssignableFrom(typeof(TUserType)))
                                {
                                    isRead = false;
                                }
                                else
                                {
                                    isRead = true;
                                }
                            }


                            argHelperType = typeof(ValueProvider <>).MakeGenericType(typeof(TAttribute), typeof(TUserType));
                        }
                        else
                        {
                            // This rule can't bind.
                            // Let another try.
                            context.BindingErrors.Add(String.Format(Resource.BindingAssemblyConflictMessage, typeof(Stream).AssemblyQualifiedName, typeof(TUserType).AssemblyQualifiedName));
                            return(null);
                        }
                    }
                }

                VerifyAccessOrThrow(declaredAccess, isRead);
                if (!parent.IsSupportedByRule(isRead))
                {
                    return(null);
                }

                var cloner = new AttributeCloner <TAttribute>(attributeSource, context.BindingDataContract, config, nm);

                ParameterDescriptor param;

                if (parent.BuildParameterDescriptor != null)
                {
                    param = parent.BuildParameterDescriptor(attributeSource, parameter, nm);
                }
                else
                {
                    param = new ParameterDescriptor
                    {
                        Name         = parameter.Name,
                        DisplayHints = new ParameterDisplayHints
                        {
                            Description = isRead ? "Read Stream" : "Write Stream"
                        }
                    };
                }

                var      fileAccess = isRead ? FileAccess.Read : FileAccess.Write;
                IBinding binding    = new StreamBinding(cloner, param, parent, argHelperType, parameterType, fileAccess, converterParam);

                return(binding);
            }
Exemple #16
0
            public static ExactBinding TryBuild(
                BindToInputBindingProvider <TAttribute, TType> parent,
                BindingProviderContext context)
            {
                var cm             = parent._converterManager;
                var patternMatcher = parent._patternMatcher;

                var parameter       = context.Parameter;
                var userType        = parameter.ParameterType;
                var attributeSource = TypeUtility.GetResolvedAttribute <TAttribute>(parameter);

                var cloner = new AttributeCloner <TAttribute>(attributeSource, context.BindingDataContract, parent._configuration, parent._nameResolver);

                FuncAsyncConverter buildFromAttribute;
                FuncAsyncConverter converter = null;

                // Prefer the shortest route to creating the user type.
                // If TType matches the user type directly, then we should be able to directly invoke the builder in a single step.
                //   TAttribute --> TUserType
                var checker = OpenType.FromType <TType>();

                if (checker.IsMatch(userType))
                {
                    buildFromAttribute = patternMatcher.TryGetConverterFunc(typeof(TAttribute), userType);
                }
                else
                {
                    // Try with a converter
                    // Find a builder for :   TAttribute --> TType
                    // and then couple with a converter:  TType --> TParameterType
                    converter = cm.GetConverter <TAttribute>(typeof(TType), userType);
                    if (converter == null)
                    {
                        var targetType = typeof(TType);
                        context.BindingErrors.Add(String.Format(Resource.BindingAssemblyConflictMessage, targetType.AssemblyQualifiedName, userType.AssemblyQualifiedName));
                        return(null);
                    }

                    buildFromAttribute = patternMatcher.TryGetConverterFunc(typeof(TAttribute), typeof(TType));
                }

                if (buildFromAttribute == null)
                {
                    return(null);
                }

                ParameterDescriptor param;

                if (parent.BuildParameterDescriptor != null)
                {
                    param = parent.BuildParameterDescriptor(attributeSource, parameter, parent._nameResolver);
                }
                else
                {
                    param = new ParameterDescriptor
                    {
                        Name         = parameter.Name,
                        DisplayHints = new ParameterDisplayHints
                        {
                            Description = "input"
                        }
                    };
                }

                return(new ExactBinding(cloner, param, buildFromAttribute, converter, userType));
            }