JSON y C# dynamic: por qué sigue siendo un dolor (y cómo tratarlo)
\n\n¿Alguna vez has mirado una respuesta JSON de una API y has pensado: «Dios mío, ¿por qué eres tan complicado?» Especialmente si la estructura de datos cambia cada vez, como el clima en San Petersburgo. Un ejemplo clásico es la respuesta de un servicio externo, donde los campos pueden ser a veces cadenas, a veces arreglos, o incluso null. O cuando necesitas analizar JSON rápidamente, pero crear una clase separada para ello es como usar un microscopio para tallar un microchip.
Precisamente para estos casos, C# tiene la magia de dynamic. La pregunta «Deserialize JSON into C# dynamic object?» en Stack Overflow ha acumulado miles de visitas, y no es casualidad. En 2025, cuando los microservicios y las API dinámicas se han convertido en la norma, la capacidad de trabajar con JSON de forma rápida y flexible es una superpotencia para el desarrollador.
En este artículo, analizaremos las mejores prácticas para deserializar JSON en un objeto dynamic en C#. Sin teoría aburrida, solo código, ejemplos y trucos reales. ¡Allá vamos!
\n\n¿Por qué dynamic? ¿Y no simplemente JObject?
\n\nBuena pregunta. En C# existen JObject (de Newtonsoft.Json) y JsonDocument (de System.Text.Json). También pueden analizar JSON «sobre la marcha». Pero dynamic ofrece algo importante: azúcar sintáctico.
Compara:
\n\n// Con JObject\nvar json = JObject.Parse(rawJson);\nvar name = (string)json["user"]["name"];\n\n// Con dynamic\ndynamic obj = JsonConvert.DeserializeObject<dynamic>(rawJson);\nvar name = obj.user.name;\n\n\nLa segunda opción se lee como código normal, no como «obtén la clave, convierte el tipo, verifica si es null». Esto es especialmente útil cuando el JSON está profundamente anidado.
\n\nMétodo 1: El clásico — Newtonsoft.Json (Json.NET)
\n\nSí, estamos en 2025, pero Newtonsoft.Json sigue vivo y coleando. Muchos proyectos heredados, e incluso algunos modernos, todavía lo usan. ¿Por qué? Flexibilidad, extensibilidad y un millón de configuraciones.
\n\nEjemplo básico
\n\nusing Newtonsoft.Json;\n\nstring json = @"\n{\n 'name': 'Alexei',\n 'age': 30,\n 'skills': ['C#', 'Python', 'SQL'],\n 'address': {\n 'city': 'Moscú',\n 'zip': 101000\n }\n}";\n\ndynamic obj = JsonConvert.DeserializeObject<dynamic>(json);\n\nConsole.WriteLine(obj.name); // Alexei\nConsole.WriteLine(obj.age); // 30\nConsole.WriteLine(obj.skills[0]); // C#\nConsole.WriteLine(obj.address.city); // Moscú\n\n\nTodo es simple y elegante. Pero hay un detalle: al trabajar con dynamic, pierdes IntelliSense y la verificación de tipos en tiempo de compilación. Un error en el nombre del campo solo se manifestará en tiempo de ejecución. Por lo tanto:
- \n
- Usa
dynamicsolo para leer datos que no controlas. \n - Envuelve siempre las llamadas en try-catch. \n
- No abuses de él: si la estructura JSON es estable, es mejor crear una clase DTO. \n
Método 2: El moderno — System.Text.Json
\n\nA partir de .NET Core 3.0, Microsoft promueve System.Text.Json: rápido, nativo, sin dependencias externas. En 2025, es el estándar para proyectos nuevos.
Pero hay un truco: System.Text.Json no puede deserializar directamente en dynamic «de fábrica». Tendrás que ingeniártelas un poco.
Opción A: A través de JsonDocument y ExpandoObject
\n\nusing System.Text.Json;\nusing System.Dynamic;\n\nstring json = @"{""name"":""Elena"",""age"":25,""active"":true}";\n\nusing JsonDocument doc = JsonDocument.Parse(json);\ndynamic obj = ConvertToExpando(doc.RootElement);\n\nConsole.WriteLine(obj.name); // Elena\nConsole.WriteLine(obj.age); // 25\nConsole.WriteLine(obj.active); // True\n\nstatic ExpandoObject ConvertToExpando(JsonElement element)\n{\n var expando = new ExpandoObject();\n var dict = (IDictionary<string, object>)expando;\n\n foreach (var property in element.Enumera