/// <summary> /// Executes the specified formatter. /// </summary> /// <param name="formatter">The formatter.</param> /// <param name="sourceObject">The source object.</param> /// <param name="templateArguments">The template arguments.</param> /// <returns></returns> public virtual async Task <object> Execute(FormatTemplateElement formatter, object sourceObject, params KeyValuePair <string, object>[] templateArguments) { var values = ComposeValues(formatter, sourceObject, templateArguments); if (values == null) { Log(() => "Skip: Execute skip as Compose Values returned an invalid value"); return(FormatterFlow.Skip); } if (formatter.CanFormat != null) { if (!formatter.CanFormat(sourceObject, templateArguments)) { Log(() => "Skip: Execute skip as CanExecute is false."); return(FormatterFlow.Skip); } } Log(() => $"Execute"); var taskAlike = formatter.Format.DynamicInvoke(values.Select(e => e.Value).ToArray()); return(await taskAlike.UnpackFormatterTask()); }
/// <summary> /// Adds the formatter. /// </summary> /// <param name="formatter">The formatter.</param> public virtual FormatTemplateElement AddFormatter(FormatTemplateElement formatter) { if (ReplaceExisting) { Formatter.Remove(Formatter.FirstOrDefault(e => e.InputTypes == formatter.InputTypes)); } Formatter.Add(formatter); return(formatter); }
/// <summary> /// Executes the specified formatter. /// </summary> /// <param name="formatter">The formatter.</param> /// <param name="sourceObject">The source object.</param> /// <param name="templateArguments">The template arguments.</param> /// <returns></returns> public virtual object Execute([NotNull] FormatTemplateElement formatter, [CanBeNull] object sourceObject, params KeyValuePair <string, object>[] templateArguments) { var values = ComposeValues(formatter, sourceObject, templateArguments); if (values == null) { Write(() => "Skip: Execute skip as Compose Values returned an invalid value"); return(FormatterFlow.Skip); } if (formatter.CanFormat != null) { if (!formatter.CanFormat(sourceObject, templateArguments)) { Write(() => "Skip: Execute skip as CanExecute is false."); return(FormatterFlow.Skip); } } Write(() => $"Execute"); return(formatter.Format.DynamicInvoke(values.Select(e => e.Value).ToArray())); }
/// <summary> /// Composes the values into a Dictionary for each formatter. If returns null, the formatter will not be called. /// </summary> /// <param name="formatter">The formatter.</param> /// <param name="sourceObject">The source object.</param> /// <param name="templateArguments">The template arguments.</param> /// <returns></returns> public virtual IDictionary <MultiFormatterInfo, object> ComposeValues([NotNull] FormatTemplateElement formatter, [CanBeNull] object sourceObject, [NotNull] params KeyValuePair <string, object>[] templateArguments) { Write(() => $"Compose values for object '{sourceObject}' with formatter '{formatter.InputTypes}' targets '{formatter.Format.Method.Name}'"); var values = new Dictionary <MultiFormatterInfo, object>(); var matched = new Dictionary <MultiFormatterInfo, KeyValuePair <string, object> >(); foreach (var multiFormatterInfo in formatter.MetaData.Where(e => !e.IsRestObject)) { Write(() => $"Match parameter '{multiFormatterInfo.Type}' [{multiFormatterInfo.Name}]"); object givenValue; //set ether the source object or the value from the given arguments if (multiFormatterInfo.IsSourceObject) { Write(() => "Is Source object"); givenValue = sourceObject; } else { //match by index or name Write(() => "Match by Name"); //match by name var match = templateArguments.FirstOrDefault(e => !string.IsNullOrWhiteSpace(e.Key) && e.Key.Equals(multiFormatterInfo.Name)); if (default(KeyValuePair <string, object>).Equals(match)) { Write(() => "Match by Index"); //match by index var index = 0; match = templateArguments.FirstOrDefault(g => index++ == multiFormatterInfo.Index); } givenValue = match.Value; Write(() => $"Matched '{match.Key}': '{match.Value}' by Name/Index"); //check for matching types if (!multiFormatterInfo.Type.IsInstanceOfType(match.Value)) { Write(() => "Skip: Match is Invalid because types from Template and Formatter mismatch. Abort."); //The type in the template and the type defined in the formatter do not match. Abort return(null); } matched.Add(multiFormatterInfo, match); } values.Add(multiFormatterInfo, givenValue); if (multiFormatterInfo.IsOptional || multiFormatterInfo.IsSourceObject) { continue; //value and source object are optional so we do not to check for its existence } if (Equals(givenValue, null)) { Write(() => "Skip: Match is Invalid because template value is null where the Formatter does not have a optional value"); //the delegates parameter is not optional so this formatter does not fit. Continue. return(null); } } var hasRest = formatter.MetaData.FirstOrDefault(e => e.IsRestObject); if (hasRest == null) { return(values); } Write(() => $"Match Rest argument '{hasRest.Type}'"); //only use the values that are not matched. var restValues = templateArguments.Except(matched.Values); if (typeof(KeyValuePair <string, object>[]) == hasRest.Type) { //keep the name value pairs values.Add(hasRest, restValues); } else if (typeof(object[]).IsAssignableFrom(hasRest.Type)) { //its requested to transform the rest values and truncate the names from it. values.Add(hasRest, restValues.Select(e => e.Value).ToArray()); } else { Write(() => $"Skip: Match is Invalid because '{hasRest.Type}' is no supported rest parameter"); //unknown type in params argument cannot call return(null); } return(values); }
/// <summary> /// Adds the formatter. /// </summary> /// <param name="formatter">The formatter.</param> public virtual FormatTemplateElement AddFormatter([NotNull] FormatTemplateElement formatter) { Formatter.Add(formatter); return(formatter); }
/// <inheritdoc /> public async Task <object> Execute(FormatTemplateElement formatter, object sourceObject, params KeyValuePair <string, object>[] templateArguments) { await Task.CompletedTask; return(null); }
/// <inheritdoc /> public FormatTemplateElement AddFormatter(FormatTemplateElement formatter) { return(ConstructEmptyMatcher()); }