示例#1
0
        public static IEnumerable <IXamlMethod> GetMarkupExtensionProvideValueAlternatives(
            AstTransformationContext context,
            IXamlType type)
        {
            var sp = context.Configuration.TypeMappings.ServiceProvider;

            return(type.FindMethods(m =>
                                    (m.Name == "ProvideValue" || m.Name == "ProvideTypedValue") && m.IsPublic && !m.IsStatic &&
                                    (m.Parameters.Count == 0 || (m.Parameters.Count == 1 && m.Parameters[0].Equals(sp)))
                                    ));
        }
示例#2
0
        public static bool TryGetCorrectlyTypedValue(AstTransformationContext context,
                                                     IXamlAstValueNode node, IXamlType type, out IXamlAstValueNode rv)
        {
            if (type.IsAssignableFrom(node.Type.GetClrType()))
            {
                rv = node;
                return(true);
            }

            return(TryConvertValue(context, node, type, null, out rv));
        }
示例#3
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);
        }
示例#4
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());
            }
        }
示例#5
0
        public static bool TryConvertValue(AstTransformationContext context,
                                           IXamlAstValueNode node, IXamlType type, XamlAstClrProperty propertyContext,
                                           out IXamlAstValueNode rv)
        {
            rv = null;
            var cfg = context.Configuration;

            // Since we are doing a conversion anyway, it makes sense to check for the underlying nullable type
            if (type.GenericTypeDefinition?.Equals(cfg.WellKnownTypes.NullableT) == true)
            {
                type = type.GenericArguments[0];
            }


            if (cfg.CustomValueConverter?.Invoke(context, node, type, out rv) == true)
            {
                return(true);
            }

            var nodeType = node.Type.GetClrType();

            // Implicit type converters
            if (!nodeType.Equals(cfg.WellKnownTypes.String))
            {
                return(false);
            }

            if (node is XamlAstTextNode tn)
            {
                if (type.IsEnum)
                {
                    if (TypeSystemHelpers.TryGetEnumValueNode(type, tn.Text, tn, out var enumConstantNode))
                    {
                        rv = enumConstantNode;
                        return(true);
                    }
                }

                // Well known types
                if (TypeSystemHelpers.ParseConstantIfTypeAllows(tn.Text, type, tn, out var constantNode))
                {
                    rv = constantNode;
                    return(true);
                }

                if (type.FullName == "System.Type")
                {
                    var resolvedType = TypeReferenceResolver.ResolveType(context, tn.Text, false, tn, true);
                    rv = new XamlTypeExtensionNode(tn, resolvedType, type);
                    return(true);
                }

                if (cfg.WellKnownTypes.Delegate.IsAssignableFrom(type))
                {
                    var invoke   = type.FindMethod(m => m.Name == "Invoke");
                    var rootType = context.RootObject.Type.GetClrType();
                    var handler  =
                        rootType.FindMethod(tn.Text, invoke.ReturnType, false, invoke.Parameters.ToArray());
                    if (handler != null)
                    {
                        rv = new XamlLoadMethodDelegateNode(tn, context.RootObject, type, handler);
                        return(true);
                    }
                }
            }

            IXamlAstValueNode CreateInvariantCulture() =>
            new XamlStaticOrTargetedReturnMethodCallNode(node,
                                                         cfg.WellKnownTypes.CultureInfo.Methods.First(x =>
                                                                                                      x.IsPublic && x.IsStatic && x.Name == "get_InvariantCulture"), null);

            var candidates = type.Methods.Where(m => m.Name == "Parse" &&
                                                m.ReturnType.Equals(type) &&
                                                m.Parameters.Count > 0 &&
                                                m.Parameters[0].Equals(cfg.WellKnownTypes.String)).ToList();

            // Types with parse method
            var parser = candidates.FirstOrDefault(m =>
                                                   m.Parameters.Count == 2 &&
                                                   (
                                                       m.Parameters[1].Equals(cfg.WellKnownTypes.CultureInfo) ||
                                                       m.Parameters[1].Equals(cfg.WellKnownTypes.IFormatProvider)
                                                   )
                                                   )
                         ?? candidates.FirstOrDefault(m => m.Parameters.Count == 1);

            if (parser != null)
            {
                var args = new List <IXamlAstValueNode> {
                    node
                };
                if (parser.Parameters.Count == 2)
                {
                    args.Add(CreateInvariantCulture());
                }

                rv = new XamlStaticOrTargetedReturnMethodCallNode(node, parser, args);
                return(true);
            }

            if (cfg.TypeMappings.TypeDescriptorContext != null)
            {
                IXamlType converterType = null;
                if (propertyContext?.TypeConverters.TryGetValue(type, out converterType) != true)
                {
                    var typeConverterAttribute =
                        cfg.GetCustomAttribute(type, cfg.TypeMappings.TypeConverterAttributes).FirstOrDefault();
                    if (typeConverterAttribute != null)
                    {
                        converterType = TryGetTypeConverterFromCustomAttribute(cfg, typeConverterAttribute);
                    }
                }

                if (converterType != null)
                {
                    var converterMethod = converterType.FindMethod("ConvertFrom", cfg.WellKnownTypes.Object, false,
                                                                   cfg.TypeMappings.TypeDescriptorContext, cfg.WellKnownTypes.CultureInfo,
                                                                   cfg.WellKnownTypes.Object);
                    rv = new XamlAstNeedsParentStackValueNode(node,
                                                              new XamlAstRuntimeCastNode(node,
                                                                                         new XamlStaticOrTargetedReturnMethodCallNode(node, converterMethod,
                                                                                                                                      new[]
                    {
                        new XamlAstNewClrObjectNode(node,
                                                    new XamlAstClrTypeReference(node, converterType, false), null,
                                                    new List <IXamlAstValueNode>()),
                        new XamlAstContextLocalNode(node, cfg.TypeMappings.TypeDescriptorContext),
                        CreateInvariantCulture(), node
                    }), new XamlAstClrTypeReference(node, type, false)));
                    return(true);
                }
            }

            return(false);
        }
 public Visitor(AstTransformationContext context, IXamlAstTransformer transformer)
 {
     _context     = context;
     _transformer = transformer;
 }