Подводный камень интерполяции строк

Рассмотрим строку:

"{0} Client called server Method: {1}) Returned: {2} Status: {3}.", 
                    session.GetClientInfo(), request, response, status

$"{session.GetClientInfo()} Client called server Method: {request}) Returned: {response} Status: {status}."

Оказывается, что в request, response, status может оказаться какая-либо пара (а может и одинарная, не проверял) фигурных скобок. В этом случае повторное форматирование может привести к ошибкам.

Когда это происходит? Например если у нас есть функция типа этой:

static void outMessage(LogFilter type, LogLevel level, string text, params object[] args)
{
    Logger logger = GetLoggerByType(type);
    logger.write(new LogMessage(level, type, string.Format(text, args)));
}

Если в качестве аргумента будет строка с фигурными скобками, внутри которых есть выражение с неопознаваемым форматом, например: введите сюда описание изображения

{{ "useBindlessRpc": true, "meteringLevel": "METERING_LEVEL_LEGACY", "clientSdkInfo": { "sdkName": "BGS C++ SDK", "sdkVersion": { "majorVersion": 6, "minorVersion": 2, "patchVersion": 0, "versionString": "6.2.0" }, "protocolVersion": { "majorVersion": 3, "minorVersion": 11, "patchVersion": 10, "versionString": "3.11.10-44dad063b5" } } }}

То вы можете получить ошибку: введите сюда описание изображения

Почему такая функция существует вообще:

  1. Наверное создавалась во времена, до введения интерполяции
  2. Поддержка обоих вариантов
  3. Возможно предполагалась поддержка комбинированного варианта (не очень хорошая идея, потому как в этом случае ошибки точно не избежать)

Откуда могут взяться фигурные скобки в переменной:

  1. Ввод с клавиатуры
  2. результат сериализации
  3. из любого другого места

Также возможно проблема может возникнуть из-за этого при наличии внутри скобок: Prior to C# 10, if an interpolated string has the type string, it's typically transformed into a String.Format method call. The compiler may replace String.Format with String.Concat if the analyzed behavior would be equivalent to concatenation.

Помогает ли экранирование скобок? - не пробовал, но в коде C# запрещает их экранировать

Вопрос: Что делать в таком случае?

UPD: Вот на этой платформе , а также на данной машине ошибка не возникает. Можно предположить что эта ошибка зависит от "Бог знает чего". Я остановился на предположении, что зависит от кодировки. Вот по сообщению ошибки требуется ASCII, хотя вроде как по умолчанию UTF16. Почему там именно такая кодировка требуется - я не знаю. Может это не правильная ошибка вовсе. Устал тыкать дебаггер. Если кому интересно - можете сами поковырять.

введите сюда описание изображения


Ответы (2 шт):

Автор решения: Artem

Изменить метод, например вот так:

static void outMessage(LogFilter type, LogLevel level, string text, params object[] args)
{
    Logger logger = GetLoggerByType(type);

    string result = args.Length > 0 ? string.Format(text, args) : text;

    logger.write(new LogMessage(level, type, result));
}
→ Ссылка
Автор решения: Pavel Mayorov

Перегрузите метод, сделав перегрузу без форматирования.

Например, так:

static void outMessage(LogFilter type, LogLevel level, string text)
{
    Logger logger = GetLoggerByType(type);
    logger.write(new LogMessage(level, type, text));
}

Если нет возможности отказаться от форматирования (скажем, оно закопано слишком глубоко) - можно принимать FormattableString:

static void outMessage(LogFilter type, LogLevel level, FormattableString text)
{
    outMessage(type, level, text.Format, text.GetArguments());
}
→ Ссылка