2008-10-14 17 views
8

Dado que los inicializadores de objetos son muy similares a JSON, y ahora hay tipos anónimos en .NET. Sería genial poder tomar una cadena, como JSON, y crear un objeto anónimo que represente la cadena JSON.¿Puedes crear una instancia de objeto de JSON en .NET?

Inicializadores Uso objeto para crear un tipo anónimo:

var person = new { 
    FirstName = "Chris", 
    LastName = "Johnson" 
}; 

Sería increíble si pudiera pasar en una representación de cadena del código inicializador (preferentemente algo así como JSON) Object para crear una instancia de un Anónimo Escriba con esa información.

No sé si es posible, ya que C# no es dinámico, y el compilador realmente convierte el Inicializador de objetos en d Anonymous Type into strongly typed code that can run. This is explained in este artículo.

Quizás la funcionalidad para tomar JSON y crear un diccionario de clave/valor con ella funcione mejor.

Sé que puede serializar/deserializar un objeto a JSON en .NET, pero lo que busco es una forma de crear un objeto que, en esencia, está tipeado libremente, de forma similar a cómo funciona JavaScript.

¿Alguien sabe la mejor solución para hacer esto en .NET?

ACTUALIZACIÓN: aclarar el contexto de por qué estoy preguntando esto ... Estaba pensando en cómo C# podría soportar mejor JSON en el nivel de idioma (posiblemente) y estaba tratando de pensar en la forma en que podría hacerse hoy, por razones conceptuales. Entonces, pensé que lo publicaría aquí para comenzar una discusión.

Respuesta

6

hay lenguajes de .NET que tienen de pato a escribir, pero no es posible con el uso de C# Dot.Notation ya que C# requiere que todas las referencias miembros se resuelven en tiempo de compilación. Si desea utilizar la Dot.Notation, aún debe definir una clase en alguna parte con las propiedades requeridas, y utilizar el método que desee para crear una instancia de la clase a partir de los datos JSON.La predefinición de una clase tiene tiene ventajas como tipeo fuerte, soporte IDE incluyendo intellisense, y no preocuparse por errores ortográficos. Puede seguir utilizando los tipos anónimos:

T deserialize<T>(string jsonStr, T obj) { /* ... */} 

var jsonString = "{FirstName='Chris', LastName='Johnson, Other='unused'}"; 
var person  = deserialize(jsonString, new {FirstName="",LastName=""}); 
var x   = person.FirstName; //strongly-typed 
+0

+1, sucio, pero actualmente es la única forma de hacer lo que el OP quiere. – user7116

+0

Muy bien, esa es una forma en la que no pensé. –

+0

¿cuál cree que sería la respuesta desde ahora C# admite tipos dinámicos –

0

¿Cuál es la aplicación para esto?

No iría por este camino por algunas razones.

  • Primero; puede requerir una gran cantidad de código de soporte utilizando la reflexión y tal para crear el método transparente del que está hablando.

  • En segundo lugar, como usted dijo, C# es un lenguaje muy tipado y cosas como estas se quedaron fuera de las especificaciones del lenguaje por una razón.

  • En tercer lugar, la sobrecarga por hacer esto no valdría la pena. Recuerde que las páginas web (especialmente las consultas AJAX) deben ser realmente rápidas o que fracasen en el propósito. Si continúas y pasas el 50% serializando tus objetos entre C# y Javascript, entonces tienes un problema.

Mi solución sería crear una clase que simplemente encapsule un diccionario y que tome una cadena JSON como argumento ctor. A continuación, amplíe esa clase para cada tipo de consulta JSON que desee controlar. Esta será una solución fuertemente tipada y más rápida, pero aún así mantendrá la extensibilidad y la facilidad de uso. La desventaja es que hay más código para escribir por tipo de solicitud JSON.

:)

5

usted debe comprobar fuera de la JSON.net proyecto:

http://james.newtonking.com/pages/json-net.aspx

que son básicamente hablando de la capacidad de hidratar un objeto de JSON, que esto lo hara. No hará los tipos anónimos, pero tal vez te acerque lo suficiente.

1

No se puede devolver un tipo anónimo de un método **, por lo que la existencia de un tipo anónimo "rehidratado" se limitaría al método en el que se rehidrata. Algo sin sentido.

** Puede devolverlo como un objeto (que requiere reflexión para acceder a sus propiedades - yeech) o puede "lanzarlo con el ejemplo", lo cual es inútil, dado que requiere pasos adicionales y significa que ya SABE cómo debe ser el tipo de objeto, entonces ¿por qué no simplemente crear un objeto y llenarlo en primer lugar?

4

Escribí un método relativamente corto que analizará JSON y devolverá un diccionario de nombre/valor al que se puede acceder de forma similar al objeto real en JavaScript.

Aquí hay un ejemplo de uso del método siguiente:

var obj = ParseJsonToDictionary("{FirstName: \"Chris\", \"Address\":{Street:\"My Street\",Number:123}}"); 

// Access the Address.Number value 
object streetNumber = ((Dictionary<string, object>)obj["Address"])["Number"]; 

Y, aquí está el código para el método ParseJsonToDictionary:

public static Dictionary<string, object> ParseJsonToDictionary(string json) 
{ 
    var d = new Dictionary<string, object>(); 

    if (json.StartsWith("{")) 
    { 
     json = json.Remove(0, 1); 
     if (json.EndsWith("}")) 
      json = json.Substring(0, json.Length - 1); 
    } 
    json.Trim(); 

    // Parse out Object Properties from JSON 
    while (json.Length > 0) 
    { 
     var beginProp = json.Substring(0, json.IndexOf(':')); 
     json = json.Substring(beginProp.Length); 

     var indexOfComma = json.IndexOf(','); 
     string endProp; 
     if (indexOfComma > -1) 
     { 
      endProp = json.Substring(0, indexOfComma); 
      json = json.Substring(endProp.Length); 
     } 
     else 
     { 
      endProp = json; 
      json = string.Empty; 
     } 

     var curlyIndex = endProp.IndexOf('{'); 
     if (curlyIndex > -1) 
     { 
      var curlyCount = 1; 
      while (endProp.Substring(curlyIndex + 1).IndexOf("{") > -1) 
      { 
       curlyCount++; 
       curlyIndex = endProp.Substring(curlyIndex + 1).IndexOf("{"); 
      } 
      while (curlyCount > 0) 
      { 
       endProp += json.Substring(0, json.IndexOf('}') + 1); 
       json = json.Remove(0, json.IndexOf('}') + 1); 
       curlyCount--; 
      } 
     } 

     json = json.Trim(); 
     if (json.StartsWith(",")) 
      json = json.Remove(0, 1); 
     json.Trim(); 


     // Individual Property (Name/Value Pair) Is Isolated 
     var s = (beginProp + endProp).Trim(); 


     // Now parse the name/value pair out and put into Dictionary 
     var name = s.Substring(0, s.IndexOf(":")).Trim(); 
     var value = s.Substring(name.Length + 1).Trim(); 

     if (name.StartsWith("\"") && name.EndsWith("\"")) 
     { 
      name = name.Substring(1, name.Length - 2); 
     } 

     double valueNumberCheck; 
     if (value.StartsWith("\"") && value.StartsWith("\"")) 
     { 
      // String Value 
      d.Add(name, value.Substring(1, value.Length - 2)); 
     } 
     else if (value.StartsWith("{") && value.EndsWith("}")) 
     { 
      // JSON Value 
      d.Add(name, ParseJsonToDictionary(value)); 
     } 
     else if (double.TryParse(value, out valueNumberCheck)) 
     { 
      // Numeric Value 
      d.Add(name, valueNumberCheck); 
     } 
     else 
      d.Add(name, value); 
    } 

    return d; 
} 

Sé que este método puede ser un poco difícil, y podría Probablemente se optimice un poco, pero es el primer borrador y simplemente funciona.

Además, antes de quejarse de que no usa expresiones regulares, tenga en cuenta que no todo el mundo realmente entiende las expresiones regulares, y escribirlo de esa manera dificultaría a otros la reparación si fuera necesario. Además, actualmente no sé demasiado bien la expresión regular, y el análisis de cadenas fue simplemente más fácil.

+0

@Gracias Chris por un código tan agradable para analizar Json String –

Cuestiones relacionadas