Могу ли я использовать Razor (или аналогичный) в обычном классе .NET, то есть получить некоторую интерполяцию строк? - PullRequest
1 голос
/ 23 октября 2010

Я мог бы поклясться, что недавно видел несколько статей о несовершенных, но полезных методах интерполяции строк для Си, но сейчас мне не повезло. Однако есть Razor, которая делает более или менее то, что я хочу.

Предположим, у вас есть клиентское приложение базы данных с тикетами, а уведомления по электронной почте необходимо отправлять при создании тикетов, значительных изменениях параметров и т. П. сообщения электронной почты, что было бы проще всего с использованием строковой интерполяции, то есть доступа к различным свойствам объекта ticket из строки, например:

Уважаемый @user,

билет @ticket.ID (@ticket.URL) имеет приоритет с @previousTicket.priority на @currentTicket.priority.

Мне бы хотелось, чтобы метод передавал различные объекты (в данном случае user, oldTicket и ticket), позволял ему оценивать строку и получать необходимые свойства посредством отражения.

Ответы [ 4 ]

2 голосов
/ 23 октября 2010

Вы можете использовать простой шаг замены для достижения простой функциональности замены ключевого слова.

Просто замените ваши ключевые слова на {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

Это предполагает, что у вас есть четко определенное и ограниченное количество ключевых слов.

1 голос
/ 23 октября 2010

Хотя я уверен, что есть много движков, которые делают это, мы остановились на Castle NVelocity, и он делает это очень хорошо.

http://www.castleproject.org/others/nvelocity/usingit.html

Он принимает данные через пары имя / значение и запускает их через шаблон. Он может быть использован для генерации всех видов текстового вывода в памяти. Поддерживаются включения, условные разделы, а также повторяющиеся данные (например, строки в заказе).

Самое главное, это чертовски просто в использовании.

0 голосов
/ 11 октября 2011
0 голосов
/ 23 октября 2010

Я не видел двух ответов, поэтому я пошел дальше и выполнил свою собственную реализацию:

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;
        }
    }
}

А вот тест:

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)
            ));
        }
    }
}

Это немного большекод, чем вариант Альбина, но не требует ручной настройки идентификаторов (хотя все равно необходимо заранее знать, какие объекты «экспортировать» для возможной интерполяции).

Спасибо, ребята!

...