Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/321.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 我可以在常规的.NET类中使用Razor(或类似的)吗?例如,获取各种字符串插值?_C#_.net 3.5_Sqlclr_String Interpolation - Fatal编程技术网

C# 我可以在常规的.NET类中使用Razor(或类似的)吗?例如,获取各种字符串插值?

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

我可以发誓我刚才看到了一些关于C语言中不完美但有用的字符串插值方法的文章,但是现在没有这样的运气。然而,有一种剃须刀,它或多或少能满足我的需求

假设您有一个带有票证的数据库客户端应用程序,并且每当创建票证、重要参数更改等时都会发送电子邮件通知。用户希望自定义这些通知电子邮件的措辞,这将使用字符串插值最简单,即,从字符串中访问
票证
对象的各种属性,如下所示:

亲爱的
@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)
            ));
        }
    }
}