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)); }
// Parse the signature to determine which mode this is. // Can also check with converter manager to disambiguate some cases. private CollectorBindingPattern GetMode(ParameterInfo parameter) { Type parameterType = parameter.ParameterType; if (parameterType.IsGenericType) { var genericType = parameterType.GetGenericTypeDefinition(); var elementType = parameterType.GetGenericArguments()[0]; if (genericType == typeof(IAsyncCollector <>)) { return(new CollectorBindingPattern(Mode.IAsyncCollector, elementType)); } else if (genericType == typeof(ICollector <>)) { return(new CollectorBindingPattern(Mode.ICollector, elementType)); } // A different interface. Let another rule try it. return(null); } if (parameter.IsOut) { // 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 Type elementType = parameter.ParameterType.GetElementType(); bool hasConverter = this._converterManager.HasConverter <TAttribute>(elementType, typeof(TType)); if (hasConverter) { // out T, where T might be an array return(new CollectorBindingPattern(Mode.OutSingle, elementType)); } if (elementType.IsArray) { // out T[] var messageType = elementType.GetElementType(); return(new CollectorBindingPattern(Mode.OutArray, messageType)); } var validator = ConverterManager.GetTypeValidator <TType>(); if (validator.IsMatch(elementType)) { // out T, t is not an array return(new CollectorBindingPattern(Mode.OutSingle, elementType)); } // For out-param ,we don't expect another rule to claim it. So give some rich errors on mismatch. 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."); } } // No match. Let another rule claim it return(null); }
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)); }