public static bool TryConvertMarkupExtension(AstTransformationContext context, IXamlAstValueNode node, out XamlMarkupExtensionNode o) { var cache = context.GetOrCreateItem <MarkupExtensionProvideValueCache>(); o = null; var nodeType = node.Type.GetClrType(); if (!cache.TypeToProvideValue.TryGetValue(nodeType, out var provideValue)) { var candidates = GetMarkupExtensionProvideValueAlternatives(context, nodeType).ToList(); var so = context.Configuration.WellKnownTypes.Object; var sp = context.Configuration.TypeMappings.ServiceProvider; // Try non-object variant first and variants without IServiceProvider argument first provideValue = candidates.FirstOrDefault(m => m.Parameters.Count == 0 && !m.ReturnType.Equals(so)) ?? candidates.FirstOrDefault(m => m.Parameters.Count == 0) ?? candidates.FirstOrDefault(m => m.Parameters.Count == 1 && m.Parameters[0].Equals(sp) && !m.ReturnType.Equals(so)) ?? candidates.FirstOrDefault(m => m.Parameters.Count == 1 && m.Parameters[0].Equals(sp)); cache.TypeToProvideValue[nodeType] = provideValue; } if (provideValue == null) { if (node.Type.IsMarkupExtension) { throw new XamlParseException( $"{node.Type.GetClrType().GetFqn()} was resolved as markup extension, but doesn't have a matching ProvideValue/ProvideTypedValue method", node.Type); } return(false); } o = new XamlMarkupExtensionNode(node, provideValue, node); return(true); }
public static IReadOnlyList <IXamlMethod> FindPossibleAdders(AstTransformationContext context, IXamlType type) { IReadOnlyList <IXamlMethod> FindPossibleAddersImpl() { var known = context.Configuration.WellKnownTypes; // Attempt to cast IEnumerable and IEnumerable<T> to IList<T> var actualType = type; if (actualType.Equals(known.IEnumerable)) { actualType = known.IList; } if (actualType.GenericTypeDefinition?.Equals(known.IEnumerableT) == true) { actualType = known.IListOfT.MakeGenericType(actualType.GenericArguments[0]); } var inspectTypes = new List <IXamlType>(); inspectTypes.Add(actualType); inspectTypes.AddRange(actualType.GetAllInterfaces()); // If type supports IList<T> don't fall back to IList if (inspectTypes.Any(t => t.GenericTypeDefinition?.Equals(known.IListOfT) == true)) { inspectTypes = inspectTypes.Where(t => !t.Equals(known.IList)).ToList(); } var rv = new List <IXamlMethod>(); foreach (var t in inspectTypes) { foreach (var m in t.FindMethods(m => m.Name == "Add" && m.IsPublic && !m.IsStatic && (m.Parameters.Count == 1 || m.Parameters.Count == 2))) { if (rv.Any(em => em.Equals(m))) { continue; } rv.Add(m); } } // First use methods from the type itself, then from base types, then from interfaces rv = rv .OrderByDescending(x => x.ThisOrFirstParameter().Equals(actualType)) .ThenBy(x => x.ThisOrFirstParameter().IsInterface) .ToList(); // Add casts for (var c = 0; c < rv.Count; c++) { if (!rv[c].ThisOrFirstParameter().Equals(type)) { rv[c] = new XamlMethodWithCasts(rv[c], new[] { type }.Concat(rv[c].Parameters)); } } return(rv); } var cache = context.GetOrCreateItem <AdderCache>(); if (cache.TryGetValue(type, out var rvr)) { return(rvr); } else { return(cache[type] = FindPossibleAddersImpl()); } }