ValueTuples теряют имена своих свойств при сериализации

При попытке сериализовать кортеж с именованным значением в строку JSON, он теряет имена, присвоенные элементам

(string type, string text) myTypes = ("A", "I am an animal");
var cnvValue = JsonConvert.SerializeObject(myTypes);

Я ожидаю сериализованное значение как

{"type": "A", "text": "Я животное"}

но фактические результаты

{"Item1": "A", "Item2": "Я животное"}

Есть две вещи, которые мне интересно знать

  • Почему это ведет себя так
  • Как получить ожидаемый результат

Ответ 1

Как получить ожидаемый результат

Что-то вроде этого:

var myTypes = new{ type = "A", text = "I am an animal"};
var cnvValue = JsonConvert.SerializeObject(myTypes);

должно работать, если вы ищете такой же краткий подход. Не использует ValueTuple (но анонимные типы) под капотом, хотя; это моя интерпретация вашего вопроса как "как я могу создать этот ожидаемый JSON без полной декларации класса и т.д."

Ответ 2

Имена - это трюк с компилятором. Если вы посмотрите на определение для ValueTuple то увидите, что его именами полей являются просто Item1, Item2 и т.д.

Поскольку JsonConvert.SerializeObject был скомпилирован задолго до того, как вы назначили имена, которые вы могли бы использовать во время компиляции, он не может восстановить имена.

Параметры метода/возвращаемые типы украшены атрибутами, которые указывают имена, которые будут использоваться, когда сигнатура метода включает ValueTuple s. Это позволяет коду, созданному позже, "видеть" имена, которые компилятор снова выполняет, но это "неправильный путь" может быть здесь очень полезным.

Как получить ожидаемый результат

Введите явный тип, если имена полей/свойств так важны.

Ответ 3

Как получить ожидаемый результат

Используйте явный пользовательский тип или анонимный класс, как в ответе @Caius.

Или вообще не создавайте для него специальный тип (для компилятора анонимного типа для вас создается класс за кулисами) и используйте JObject для динамического создания json:

var myTypesJson = new JObject(
    new JProperty("type", "A"), 
    new JProperty("text", "I am an animal")
);
var cnvValue = myTypesJson.ToString();

или используйте для него индексатор и синтаксис инициализации:

var createdJson = new JObject()
{
    ["type"] = "A",
    ["text"] = "I am an animal"
};
var cnvValue = createdJson.ToString();