예제 #1
0
        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);
        }
예제 #2
0
        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());
            }
        }