В конфигурационном JSON файле используются строки следующего вида:
{
"logFilePattern" : "{yyyy}.{mm}.{dd}.log"
}
Для замены используется множество разных текстовых заполнителей: вычисляемые пути файловой системы, которые зависят от пользователя и т.д.. Предполагается их замена и для этого в предыдущих версиях C# использовалось составное форматирование (могу ошибаться в термине) таким образом:
string name = "Fred";
Console.WriteLine(String.Format("Name = {0}", name));
// output: "Name = Fred"
С выходом C# 6 версии появилась возможность использовать именованные аргументы (могу ошибаться в термине) таким образом:
string name = "Fred";
Console.WriteLine($"Name = {name}");
// output: "Name = Fred"
Вопрос: как интерполировать строку с именованными аргументами сохраненую в переменной?
string stringPattern = "Name = {name}";
string name = "Fred";
// ?
Нашел здесь что это не возможно, т.к. код:
string name = "Fred";
string name2 = $"Name = {name}";
, компилятором приводится к:
string name = "fred";
string name2 = String.Format("Name = {0}", name);
Другим словами, это просто синтаксический сахар.
UPD
Если весь вопрос в том, как сгенерировать имя лог файла, то может проще обойтись таким способом? В конфигурации задаем валидный с т.з. .NET формат для даты:
{
"logFilePattern" : "yyyy.MM.dd.log"
}
Затем в коде выкусываем его и получаем имя файла:
const string extension = ".log";
var datePattern = logFilePattern.Remove(logFilePattern.IndexOf(extension), extension.Length);
DateTime date = DateTime.UtcNow;
var logFileName = date.ToString(datePattern) + extension;
О задаче в общем
Наивная реализация может состоять просто в замене значения:
string stringPattern = "Name = {name}";
string name = "Fred";
string formatted = stringPattern.Replace($"{{nameof(name)}}", name);
Тут есть два недостатка:
FormatString(pattern, value1, value2, ...)
)"{{name}}"
не является шаблоном, однако замена будет произведена)Метод вида FormatString(pattern, value1, value2, ...)
, насколько я понимаю, нереален, поскольку нет способа в вызываемом методе узнать имена параметров, с которыми он вызывался. Поэтому можно остановиться на, например, словаре:
public static string FormatString(string pattern, IDictionary<string, object> values)
Эскапирование можно обработать регулярным выражением, но учитывая, что параметров может быть несколько, это тоже может быть излишне тяжелой операцией. Поэтому реализация в общем-то зависит от желаемой степени оптимизированности, в идеале надо вручную проходить char[]
/List<char>
и менять его на ходу.
На ночь глядя получилось так:
public static string FormatString(string pattern, IDictionary<string, object> values)
{
var buffer = pattern.ToList();
int replaceStartIndex = -1;
int replaceEndIndex = -1;
int index = 0;
while (index < buffer.Count)
{
var character = buffer[index];
if (character == '{')
{
if (replaceStartIndex == -1)
{
replaceStartIndex = index;
}
else
{
replaceStartIndex = -1;
}
}
else if (character == '}')
{
if (replaceEndIndex == -1)
{
replaceEndIndex = index;
}
else
{
replaceEndIndex = -1;
}
}
if (replaceStartIndex > -1 && replaceEndIndex > -1)
{
var key = new string(buffer.Skip(replaceStartIndex + 1).Take(replaceEndIndex - replaceStartIndex - 1).ToArray());
var value = values[key];
var stringValue = value?.ToString();
buffer.RemoveRange(replaceStartIndex, replaceEndIndex - replaceStartIndex + 1);
if (stringValue != null)
{
buffer.InsertRange(replaceStartIndex, stringValue.ToCharArray());
index = replaceStartIndex + stringValue.Length;
}
else
{
index = replaceStartIndex;
}
replaceStartIndex = -1;
replaceEndIndex = -1;
}
else
{
index++;
}
}
return string.Join("", buffer);
}
Проверка:
static void Main(string[] args)
{
string stringPattern = "Name = {name}, Age = {age}, Null = {nullString}, Escape = {{escape}}";
string name = "Fred";
int age = 42;
string nullString = null;
string escape = "You shouldn't see this";
var values = new Dictionary<string, object>()
{
[nameof(name)] = name,
[nameof(age)] = age,
[nameof(nullString)] = nullString,
[nameof(escape)] = escape
};
string formatted = FormatString(stringPattern, values);
Console.WriteLine(formatted);
}
Вывод:
Name = Fred, Age = 42, Null = , Escape = {{escape}}
Вот тут сказано, что приведенная в топике строка является типом System.FormattableString
.
По поводу которого читаем что можно получить по индексу нужный инжектированный параметр. И просто можем сформировать новую строку со своим инжектом.
Это возможно в рамках передаваемой интерполированной строки в функцию, например..
Возможно таким способом получить нужный результат?!
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
Нужно вывести окно поверх всех окон, для эффекта водяного знакаВозможно ли это сделать с помощью WPF без использования WinApi?
Нужно разработать мультиплатформенное десктопное(в будущем возможно и мобила) приложениеВыбрал Xamarin Forms, он только для мобильных приложений?...
Хотите улучшить этот вопрос? Добавьте больше подробностей и уточните проблему, отредактировав это сообщение