【问题标题】:Template Parsing and Reflection模板解析和反射
【发布时间】:2009-11-16 14:29:04
【问题描述】:

我正在用 ASP.NET/C# 编写一个内容管理系统,该网站的模板在 html 文件中定义。我正在使用 blocks 将参数传递给 html 文件。一个块以 [ 开头并以 ] 结尾。带有一些简单块的模板示例:

<html>
<head>
    <title>[Title]</title>
    <meta name="description" content="[Description]" />
</head>
<body>
    <h1>[Headline]</h1>
    <p>[Text]</p>
</body>  
</html>

现在,我有一个代表模板的类。示例模板的类如下所示:

public class MyTemplate
{
    public string Title
    {
        get;
        set;
    }

    public string Description
    {
        get;
        set;
    }

    public string Headline
    {
        get;
        set;          
    }

    public string Text
    {
        get;
        set;          
    }
}

该类可以是我编写的类、由 Linq To SQL 生成的类或任何类。

我创建了一个用属性值替换块的方法。为此,我正在使用正则表达式:

    public static string ParseTemplateFromObject(string input, object obj)
    {
        return Regex.Replace(input, @"\[(.*?)\]", new MatchEvaluator(delegate(Match match)
        {
            var blockName = match.Result("$1");

            return obj.GetType().GetProperties().SingleOrDefault(p => p.Name.Equals(blockName, StringComparison.OrdinalIgnoreCase))
                .GetValue(obj, null).ToString();

        }), RegexOptions.Multiline);
    }

...它正在工作。我使用 GetProperties() 然后 Linq 而不是 GetProperty 来防止区分大小写。但是现在我有另一个问题,当我想在一个块中使用参数时。例如:我想创建一个垂直菜单。系统中的菜单可以是垂直的也可以是水平的:

[Menu Id=1, Direction="Vertical"]

所以,我决定这种类型的块调用一个方法并提取它的值,而不是从它的属性中提取值。示例:

public class MyTemplate
{
    ...
    public string Menu(int id, string direction)
    {
        string menu = ...;
        return menu;
    }
}

我扩展了我的ParseTemplateFromObject 来支持这个:

    public static string ParseTemplateFromObject(string input, object obj)
    {
        return Regex.Replace(input, @"\[(.*?)\]", new MatchEvaluator(delegate(Match match)
        {
            var blockName = match.Result("$1");

            var m = Regex.Match(blockName, "(?<Name>\\w+)=((?<Value>\\w+)|\"(?<Value>([^\"]*))\")");

            if (m.Captures.Count > 0)
            {
                var method = obj.GetType().GetMethods().Single(p => p.Name.Equals(blockName.Substring(0, blockName.IndexOf(' '))
                    , StringComparison.OrdinalIgnoreCase));

                var methodParameters = method.GetParameters();
                var parameters = new object[methodParameters.Length];

                while (m.Success)
                {
                    var name = m.Groups["Name"].Value;
                    var value = m.Groups["Value"].Value;

                    var methodParameter = methodParameters.Single(p => p.Name.ToLower() == name.ToLower());
                    parameters[methodParameter.Position] =
                        Convert.ChangeType(value, methodParameter.ParameterType);

                    m = m.NextMatch();
                }

                return method.Invoke(obj, parameters).ToString();
            }
            else
            {
                return obj.GetType().GetProperties().SingleOrDefault(p => p.Name.Equals(blockName, StringComparison.OrdinalIgnoreCase))
                    .GetValue(obj, null).ToString();

            }
        }), RegexOptions.Multiline);
    }
}

它有效,但我正在寻找使其更有效的方法。而且我不知道这是否真的是实现这一点的正确方法?

谢谢。

【问题讨论】:

    标签: c# asp.net reflection templates


    【解决方案1】:

    也许使用 ASP.Net 提供的本机模板?即,使用标准 .aspx 页面定义模板,然后使用 Server.Execute 方法捕获这些页面生成的输出。您将能够使用服务器代码块 () 来 1.) 插入由后面的代码公开的变量或 2.) 在后面的代码中执行方法。将节省您更新解析代码的工作,并提供广泛认可的模板格式。

    【讨论】:

    • 尝试从控制台应用程序执行此操作时会变得一团糟
    【解决方案2】:

    您是否考虑过在实际模板中管理标记的样式,而不是在代码中设置它们的样式?例如,您有一个方向属性,它可能是我建议的方法的理想候选者。这样您就可以非常简单地解析标记。

    【讨论】:

      猜你喜欢
      • 2019-11-04
      • 2019-05-23
      • 2013-01-02
      • 2023-04-07
      • 2011-08-10
      • 2012-12-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多