Я пишу систему управления контентом в ASP.NET/C#, шаблон сайта которой определен в html-файле. Я передаю параметры в HTML-файл с blocks . Блок начинается с [ и заканчивается ] . Пример шаблона с несколькими простыми блоками:
<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"]
Итак, я решил, что этот тип блока вызывает метод и извлекает его значение вместо извлечения значения из его свойства. Пример: * +1021 *
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);
}
}
Это работает, но я ищу способы сделать его более эффективным. И я не знаю, действительно ли это правильный способ реализовать это?
Спасибо.