C# 我可以在常规的.NET类中使用Razor(或类似的)吗?例如,获取各种字符串插值?
我可以发誓我刚才看到了一些关于C语言中不完美但有用的字符串插值方法的文章,但是现在没有这样的运气。然而,有一种剃须刀,它或多或少能满足我的需求 假设您有一个带有票证的数据库客户端应用程序,并且每当创建票证、重要参数更改等时都会发送电子邮件通知。用户希望自定义这些通知电子邮件的措辞,这将使用字符串插值最简单,即,从字符串中访问C# 我可以在常规的.NET类中使用Razor(或类似的)吗?例如,获取各种字符串插值?,c#,.net-3.5,sqlclr,string-interpolation,C#,.net 3.5,Sqlclr,String Interpolation,我可以发誓我刚才看到了一些关于C语言中不完美但有用的字符串插值方法的文章,但是现在没有这样的运气。然而,有一种剃须刀,它或多或少能满足我的需求 假设您有一个带有票证的数据库客户端应用程序,并且每当创建票证、重要参数更改等时都会发送电子邮件通知。用户希望自定义这些通知电子邮件的措辞,这将使用字符串插值最简单,即,从字符串中访问票证对象的各种属性,如下所示: 亲爱的@user 票证@ticket.ID(@ticket.URL)的优先级已从@previousTicket.priority更改为@cur
票证
对象的各种属性,如下所示:
亲爱的@user
票证@ticket.ID
(@ticket.URL
)的优先级已从@previousTicket.priority
更改为@currentTicket.priority
我想要的是一种方法,我传递各种对象(在本例中是
user
,oldTicket
和ticket
),让它评估字符串并通过反射获得必要的属性。虽然我确信有很多引擎可以做到这一点,但我们选择了Castle NVelocity,而且它做得非常好
它通过名称/值对接受数据,并通过模板运行数据。它可以用于在内存中生成各种文本输出。它支持包含、条件节和重复数据(例如订单上的行)
最重要的是,它非常容易使用。您可以使用简单的替换步骤来实现简单的关键字替换功能 只需将关键字替换为
{0}
,{1}
等,并在正确的位置使用string.Format
和正确的参数即可
Dictionary<string, int> keywords = new Dictionary<string, int>();
keywords["@user"] = 0;
keywords["@ticket.ID"] = 1;
keywords["@ticket.URL"] = 2;
// etc...
string template = @"Dear @user,
the ticket @ticket.ID (@ticket.URL) has changed in priority from @previousTicket.priority to @currentTicket.priority.";
string replacedTemplate = template;
foreach (var keyword in keywords)
{
replacedTemplate = replacedTemplate.Replace(keyword.Key, "{" + keyword.Value + "}");
}
string formattedMessage = string.Format(replacedTemplate, userName, ticket.ID, ticket.URL); // corresponding to the dictionary
字典关键字=新字典();
关键词[“@user”]=0;
关键词[“@ticket.ID”]=1;
关键词[“@ticket.URL”]=2;
//等等。。。
字符串模板=@“亲爱的@用户,
票证@ticket.ID(@ticket.URL)的优先级已从@previousTicket.priority更改为@currentTicket.priority。“;
字符串replacedTemplate=模板;
foreach(关键字中的var关键字)
{
replacedTemplate=replacedTemplate.Replace(关键字.Key,“{”+关键字.Value+“}”);
}
string formattedMessage=string.Format(replacedTemplate、用户名、ticket.ID、ticket.URL);//与字典相对应
这假设您有一个定义良好且数量有限的关键字。我没有看到这两个答案,所以我继续进行并完成了自己的实现:
using System.Collections.Generic;
using System.Text.RegularExpressions;
namespace StringInterpolation {
/// <summary>
/// An object with an explicit, available-at-runtime name.
/// </summary>
public struct NamedObject {
public string Name;
public object Object;
public NamedObject(string name, object obj) {
Name = name;
Object = obj;
}
}
public static class StringInterpolation {
/// <summary>
/// Parses a string for basic Razor-like interpolation with explicitly passed objects.
/// For example, pass a NamedObject user, and you can use @user and @user.SomeProperty in your string.
/// </summary>
/// <param name="s">The string to be parsed.</param>
/// <param name="objects">A NamedObject array for objects too allow for parsing.</param>
public static string Interpolate(this string s, params NamedObject[] objects) {
System.Diagnostics.Debug.WriteLine(s);
List<NamedObject> namedObjects = new List<NamedObject>(objects);
Dictionary<NamedObject, Dictionary<string, string>> objectsWithProperties = new Dictionary<NamedObject, Dictionary<string, string>>();
foreach (NamedObject no in objects) {
Dictionary<string, string> properties = new Dictionary<string, string>();
foreach (System.Reflection.PropertyInfo pInfo in no.Object.GetType().GetProperties())
properties.Add(pInfo.Name, pInfo.GetValue(no.Object, new object[] { }).ToString());
objectsWithProperties.Add(no, properties);
}
foreach (Match match in Regex.Matches(s, @"@(\w+)(\.(\w+))?")) {
NamedObject no;
no = namedObjects.Find(delegate(NamedObject n) { return n.Name == match.Groups[1].Value; });
if (no.Name != null && match.Groups.Count == 4)
if (string.IsNullOrEmpty(match.Groups[3].Value))
s = s.Replace(match.Value, no.Object.ToString());
else {
Dictionary<string, string> properties = null;
string value;
objectsWithProperties.TryGetValue(no, out properties);
if (properties != null && properties.TryGetValue(match.Groups[3].Value, out value))
s = s.Replace(match.Value, value);
}
}
return s;
}
}
}
它的代码比Albin的变体多得多,但不需要手动设置ID(尽管它仍然需要您提前知道要“导出”哪些对象以进行潜在插值)
谢谢大家 另请参见:请在投入生产前对此进行测试。我收到太多的
亲爱的${firstName}${lastName}。br你想买便宜的${pharmaceutical}
类邮件吗?非常有趣。我也得试一下。谢谢。:)
using StringInterpolation;
namespace StringInterpolationTest {
class User {
public string Name { get; set; }
}
class Ticket {
public string ID { get; set; }
public string Priority { get; set; }
}
class Program {
static void Main(string[] args) {
User user = new User();
user.Name = "Joe";
Ticket previousTicket = new Ticket();
previousTicket.ID = "1";
previousTicket.Priority = "Low";
Ticket currentTicket = new Ticket();
currentTicket.ID = "1";
currentTicket.Priority = "High";
System.Diagnostics.Debug.WriteLine("User: @user, Username: @user.Name, Previous ticket priority: @previousTicket.Priority, New priority: @currentTicket.Priority".Interpolate(
new NamedObject("user", user),
new NamedObject("previousTicket", previousTicket),
new NamedObject("currentTicket", currentTicket)
));
}
}
}