/// <summary> /// Gets all formatter that are invokable with on the given type and with the arguments. /// </summary> public virtual IEnumerable <MorestachioFormatterModel> PrepareGetMatchingFormatterOn( Type typeToFormat, FormatterArgumentType[] arguments, ParserOptions parserOptions, string name) { Log(parserOptions, () => $"Lookup formatter for type {typeToFormat} with name {name}", () => arguments.ToDictionary(e => e.Name, e => (object)e)); if (!Formatters.TryGetValue(name ?? "{NULL}", out var formatters)) { Log(parserOptions, () => $"There are no formatters for the name {name}"); return(Enumerable.Empty <MorestachioFormatterModel>()); } var filteredSourceList = new List <KeyValuePair <MorestachioFormatterModel, ulong> >(); foreach (var formatTemplateElement in formatters) { Log(parserOptions, () => $"Test formatter input type: '{formatTemplateElement.InputType}' on formatter named '{formatTemplateElement.Function.Name}'"); if (formatTemplateElement.InputType != typeToFormat && !formatTemplateElement.InputType.GetTypeInfo().IsAssignableFrom(typeToFormat)) { if (ValueConverter.All(e => !e.CanConvert(typeToFormat, formatTemplateElement.InputType))) { if (formatTemplateElement.MetaData.SourceObject != null && formatTemplateElement.MetaData.SourceObject.FormatterValueConverterAttribute .Select(e => e.CreateInstance()) .All(e => !e.CanConvert(typeToFormat, formatTemplateElement.InputType))) { if (!CheckGenericTypeForMatch(typeToFormat, formatTemplateElement)) { var foundInterface = false; //TODO cleanup this mess or rewrite the generic interface matching! //foreach (var @interface in typeToFormat.GetInterfaces()) //{ // if (CheckGenericTypeForMatch(@interface, formatTemplateElement)) // { // foundInterface = true; // } //} if (!foundInterface) { Log(parserOptions, () => $"Exclude because formatter accepts '{formatTemplateElement.InputType}' is not assignable from '{typeToFormat}'"); continue; } } } } } //count rest arguments //var mandatoryArguments = formatTemplateElement.MetaData // .Where(e => !e.IsRestObject && !e.IsOptional && !e.IsSourceObject && !e.IsInjected).ToArray(); if (formatTemplateElement.MetaData.MandetoryArguments.Count > arguments.Length) //if there are less arguments excluding rest then parameters { Log(parserOptions, () => "Exclude because formatter has " + $"'{formatTemplateElement.MetaData.MandetoryArguments.Count}' " + "parameter and " + $"'{formatTemplateElement.MetaData.Count(e => e.IsRestObject)}' " + "rest parameter but needs less or equals" + $"'{arguments.Length}'."); continue; } ulong score = 1L; if (formatTemplateElement.Function.ReturnParameter == null || formatTemplateElement.Function.ReturnParameter?.ParameterType == typeof(void)) { score++; } score += (ulong)(arguments.Length - formatTemplateElement.MetaData.MandetoryArguments.Count); Log(parserOptions, () => $"Take filter: '{formatTemplateElement.InputType} : {formatTemplateElement.Function}' Score {score}"); filteredSourceList.Add( new KeyValuePair <MorestachioFormatterModel, ulong>(formatTemplateElement, score)); } if (filteredSourceList.Count > 0) { var formatter = new List <MorestachioFormatterModel>(); foreach (var formatTemplateElement in filteredSourceList.OrderBy(e => e.Value)) { formatter.Add(formatTemplateElement.Key); } return(formatter); } Log(parserOptions, () => "No formatter matches"); return(Enumerable.Empty <MorestachioFormatterModel>()); }
/// <summary> /// Gets the matching formatter. /// </summary> public virtual IEnumerable <MorestachioFormatterModel> GetMatchingFormatter( [CanBeNull] object sourceValue, [NotNull] Type typeToFormat, [NotNull] KeyValuePair <string, object>[] arguments, [CanBeNull] string name) { Log(() => { var aggregate = arguments.Any() ? arguments.Select(e => $"[{e.Key}]:\"{e.Value}\"").Aggregate((e, f) => e + " & " + f) : ""; return ($"Test Filter for '{typeToFormat}' with arguments '{aggregate}'"); }); var filteredSourceList = new List <KeyValuePair <MorestachioFormatterModel, ulong> >(); foreach (MorestachioFormatterModel formatTemplateElement in Formatters) { if (!string.Equals(formatTemplateElement.Name, name, FormatterNameCompareMode)) { continue; } Log(() => $"Test filter: '{formatTemplateElement.InputType} : {formatTemplateElement.Function.Name}'"); if (formatTemplateElement.InputType != typeToFormat && !formatTemplateElement.InputType.GetTypeInfo().IsAssignableFrom(typeToFormat)) { if (ValueConverter.All(e => !e.CanConvert(sourceValue, formatTemplateElement.InputType))) { if (formatTemplateElement.MetaData.SourceValue().FormatterValueConverterAttribute.Select(e => e.CreateInstance()) .All(e => !e.CanConvert(sourceValue, formatTemplateElement.InputType))) { var typeToFormatGenerics = typeToFormat.GetTypeInfo().GetGenericArguments(); //explicit check for array support if (typeToFormat.HasElementType) { var elementType = typeToFormat.GetElementType(); typeToFormatGenerics = typeToFormatGenerics.Concat(new[] { elementType }).ToArray(); } //the type check has maybe failed because of generic parameter. Check if both the formatter and the typ have generic arguments var formatterGenerics = formatTemplateElement.InputType.GetTypeInfo().GetGenericArguments(); if (typeToFormatGenerics.Length <= 0 || formatterGenerics.Length <= 0 || typeToFormatGenerics.Length != formatterGenerics.Length) { Log(() => $"Exclude because formatter accepts '{formatTemplateElement.InputType}' is not assignable from '{typeToFormat}'"); continue; } } } } //count rest arguments var mandatoryArguments = formatTemplateElement.MetaData .Where(e => !e.IsRestObject && !e.IsOptional && !e.IsSourceObject).ToArray(); if (mandatoryArguments.Length > arguments.Length) //if there are less arguments excluding rest then parameters { Log(() => "Exclude because formatter has " + $"'{mandatoryArguments.Length}' " + "parameter and " + $"'{formatTemplateElement.MetaData.Count(e => e.IsRestObject)}' " + "rest parameter but needs less or equals" + $"'{arguments.Length}'."); continue; } ulong score = 1L; if (formatTemplateElement.Function.ReturnParameter == null || formatTemplateElement.Function.ReturnParameter?.ParameterType == typeof(void)) { score++; } score += (ulong)(arguments.Length - mandatoryArguments.Length); Log(() => $"Take filter: '{formatTemplateElement.InputType} : {formatTemplateElement.Function}' Score {score}"); filteredSourceList.Add(new KeyValuePair <MorestachioFormatterModel, ulong>(formatTemplateElement, score)); } var formatter = new List <MorestachioFormatterModel>(); foreach (var formatTemplateElement in filteredSourceList.OrderBy(e => e.Value)) { formatter.Add(formatTemplateElement.Key); } return(formatter); }
/// <summary> /// /// </summary> /// <param name="typeToFormat"></param> /// <param name="arguments"></param> /// <param name="name"></param> /// <returns></returns> public virtual IEnumerable <MorestachioFormatterModel> PrepareGetMatchingFormatterOn( [NotNull] Type typeToFormat, [NotNull] FormatterArgumentType[] arguments, [CanBeNull] string name) { var filteredSourceList = new List <KeyValuePair <MorestachioFormatterModel, ulong> >(); if (!Formatters.TryGetValue(name ?? "{NULL}", out var formatters)) { return(Enumerable.Empty <MorestachioFormatterModel>()); } foreach (var formatTemplateElement in formatters) { Log(() => $"Test filter: '{formatTemplateElement.InputType} : {formatTemplateElement.Function.Name}'"); if (formatTemplateElement.InputType != typeToFormat && !formatTemplateElement.InputType.GetTypeInfo().IsAssignableFrom(typeToFormat)) { if (ValueConverter.All(e => !e.CanConvert(typeToFormat, formatTemplateElement.InputType))) { if (formatTemplateElement.MetaData.SourceObject != null && formatTemplateElement.MetaData.SourceObject.FormatterValueConverterAttribute .Select(e => e.CreateInstance()) .All(e => !e.CanConvert(typeToFormat, formatTemplateElement.InputType))) { var typeToFormatGenerics = typeToFormat.GetTypeInfo().GetGenericArguments(); //explicit check for array support if (typeToFormat.HasElementType) { var elementType = typeToFormat.GetElementType(); typeToFormatGenerics = typeToFormatGenerics.Concat(new[] { elementType }).ToArray(); } //the type check has maybe failed because of generic parameter. Check if both the formatter and the typ have generic arguments var formatterGenerics = formatTemplateElement.InputType.GetTypeInfo().GetGenericArguments(); if (typeToFormatGenerics.Length <= 0 || formatterGenerics.Length <= 0 || typeToFormatGenerics.Length != formatterGenerics.Length) { Log(() => $"Exclude because formatter accepts '{formatTemplateElement.InputType}' is not assignable from '{typeToFormat}'"); continue; } } else { continue; } } } //count rest arguments //var mandatoryArguments = formatTemplateElement.MetaData // .Where(e => !e.IsRestObject && !e.IsOptional && !e.IsSourceObject && !e.IsInjected).ToArray(); if (formatTemplateElement.MetaData.MandetoryArguments.Count > arguments.Length) //if there are less arguments excluding rest then parameters { Log(() => "Exclude because formatter has " + $"'{formatTemplateElement.MetaData.MandetoryArguments.Count}' " + "parameter and " + $"'{formatTemplateElement.MetaData.Count(e => e.IsRestObject)}' " + "rest parameter but needs less or equals" + $"'{arguments.Length}'."); continue; } ulong score = 1L; if (formatTemplateElement.Function.ReturnParameter == null || formatTemplateElement.Function.ReturnParameter?.ParameterType == typeof(void)) { score++; } score += (ulong)(arguments.Length - formatTemplateElement.MetaData.MandetoryArguments.Count); Log(() => $"Take filter: '{formatTemplateElement.InputType} : {formatTemplateElement.Function}' Score {score}"); filteredSourceList.Add( new KeyValuePair <MorestachioFormatterModel, ulong>(formatTemplateElement, score)); } if (filteredSourceList.Count > 0) { var formatter = new List <MorestachioFormatterModel>(); foreach (var formatTemplateElement in filteredSourceList.OrderBy(e => e.Value)) { formatter.Add(formatTemplateElement.Key); } return(formatter); } return(Enumerable.Empty <MorestachioFormatterModel>()); }