Ejemplo n.º 1
0
            // Implements the @bind(...) syntax
            private bool TryAddBindExpression(RazorIRToken token)
            {
                const string bindExpressionStart = "bind(";
                const string bindExpressionEnd   = ")";

                if (token.Content.StartsWith(bindExpressionStart) && token.Content.EndsWith(bindExpressionEnd))
                {
                    // Extract "expr" from "bind(expr)"
                    var boundExpression = token.Content.Substring(
                        bindExpressionStart.Length,
                        token.Content.Length - bindExpressionStart.Length - bindExpressionEnd.Length);

                    // We can't work out the final binding expression code yet, because we don't yet know what
                    // type of element this is going onto (there might be a "type='checkbox'" or similar that
                    // appears *after* the @bind(...)). So just store the expression for later use.
                    _nextElementBoundExpression = MakeCSharpExpressionIRNode(token, boundExpression);
                    return(true);
                }

                return(false);
            }
Ejemplo n.º 2
0
        private static void AddIComponentRazorViewFactoryImplementation(ClassDeclarationIRNode classNode, RazorCodeDocument codeDoc)
        {
            // The Activator.CreateInstance feature that I added to the DNA runtime is very basic and doesn't
            // actually invoke the default constructor of the type being created. It just allocates memory for
            // the instance and returns it, without having run any constructor. This could be confusing if you
            // put constructor logic (such as field initializers) in your Razor page, given that we instantiate
            // it using Activator.CreateInstance.
            // As a workaround (without actually adding constructor support to Activator.CreateInstance, which
            // would be nontrivial), the Razor views privately implement an interface IComponentRazorViewFactory
            // that can return new instances of their own type. We can then just call this with normal .NET code.
            // This means we allocate memory for two instances of the view even though we're only using one,
            // but it's not going to matter much as the first instance will just be released to GC immediately.
            if (classNode.Interfaces == null)
            {
                classNode.Interfaces = new List <string>();
            }
            classNode.Interfaces.Add(typeof(IRazorComponentFactory).FullName);
            var methodStatement = new CSharpStatementIRNode {
                Parent = classNode, Source = null
            };

            classNode.Children.Add(methodStatement);

            var    model    = codeDoc.Items["DetectedModel"];
            string content  = "";
            string isPage   = "";
            string addItems = "";

            if (model != null)
            {
                content = $@"Model = new {model}();";
            }
            if ((bool)codeDoc.Items["DetectedPage"])
            {
                isPage += "classNode.IsPage = true;";
            }

            if ((codeDoc.Items["DetectedPageMatches"]) != null)
            {
                var list = (List <string>)codeDoc.Items["DetectedPageMatches"];
                addItems += "List<string> list = new List<string>();";
                foreach (var item in list)
                {
                    addItems += $"\r\n list.Add(\"{item}\");";
                }
                addItems += "\r\n Items = list;";
            }
            var razorToken = new RazorIRToken
            {
                Kind    = RazorIRToken.TokenKind.CSharp,
                Parent  = classNode,
                Content = $@"
                    {typeof(RazorComponent).FullName} {typeof(IRazorComponentFactory).FullName}.{nameof(IRazorComponentFactory.Instantiate)}()
                    {{
                        {content} 
                        var classNode = new {classNode.Name}();
                        {isPage}
                        {addItems}
                        return classNode;
                    }}"
            };

            methodStatement.Children.Add(razorToken);
        }