【发布时间】: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