Domanda

Poiché gli inizializzatori di oggetti sono molto simili a JSON e ora ci sono tipi anonimi in .NET. Sarebbe bello poter prendere una stringa, come JSON, e creare un oggetto anonimo che rappresenti la stringa JSON.

Utilizza gli inizializzatori di oggetti per creare un tipo anonimo:

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

Sarebbe fantastico se si potesse passare una rappresentazione in forma di stringa del codice di inizializzazione dell'oggetto (preferibilmente qualcosa come JSON) per creare un'istanza di un tipo anonimo con tali dati.

Non so se sia possibile, dal momento che C # non è dinamico e il compilatore converte effettivamente l'Inizializzatore di oggetti in d Anonimo Digitare in un codice fortemente tipizzato che può essere eseguito. Questo è spiegato in questo articolo.

Forse la funzionalità per prendere JSON e creare un dizionario chiave / valore con esso funzionerebbe meglio.

So che puoi serializzare / deserializzare un oggetto su JSON in .NET, ma quello che sto cercando è un modo per creare un oggetto che sia essenzialmente impresso in modo approssimativo, in modo simile a come funziona JavaScript.

Qualcuno conosce la migliore soluzione per farlo in .NET?

AGGIORNAMENTO: Chiarire troppo il contesto del motivo per cui lo sto chiedendo ... Stavo pensando a come C # potesse supportare meglio JSON a livello linguistico (possibilmente) e stavo cercando di pensare a come farlo oggi , per motivi concettuali. Quindi, ho pensato di pubblicarlo qui per iniziare una discussione.

È stato utile?

Soluzione

Ci sono lingue per .NET che hanno la tipizzazione duck ma non è possibile con C # usando Dot.Notation poiché C # richiede che tutti i riferimenti dei membri vengano risolti al momento della compilazione. Se si desidera utilizzare Dot.Notation, è comunque necessario definire una classe da qualche parte con le proprietà richieste e utilizzare qualsiasi metodo si desideri creare un'istanza della classe dai dati JSON. La pre-definizione di una classe ha ha vantaggi come la digitazione forte, il supporto IDE incluso l'intellisense e non preoccuparsi degli errori di ortografia. Puoi ancora utilizzare tipi anonimi:

 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

Altri suggerimenti

Dovresti dare un'occhiata al progetto JSON.net :

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

Stai fondamentalmente parlando della capacità di idratare un oggetto da JSON, cosa che farà. Non farà i tipi anonimi, ma forse ti avvicinerà abbastanza.

Ho scritto un metodo relativamente breve che analizzerà JSON e restituirà un dizionario nome / valore a cui è possibile accedere in modo simile all'oggetto reale in JavaScript.

Ecco un esempio di utilizzo del metodo seguente:

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

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

Ed ecco il codice per il metodo 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;
}

So che questo metodo potrebbe essere un po 'approssimativo e probabilmente potrebbe essere ottimizzato un po', ma è la prima bozza e funziona.

Inoltre, prima di lamentarti del fatto che non usa espressioni regolari, tieni presente che non tutti comprendono davvero le espressioni regolari, e scriverlo in questo modo renderebbe più difficile per gli altri risolvere se necessario. Inoltre, attualmente non conosco troppo bene l'espressione regolare e l'analisi delle stringhe è stata semplicemente più semplice.

Non puoi restituire un tipo anonimo da un metodo **, quindi un "reidratato" L'esistenza di un tipo anonimo sarebbe limitata al metodo in cui viene reidratata. Un po 'inutile.

** Puoi restituirlo come oggetto (che richiede la riflessione per accedere alle sue proprietà - yeech) oppure puoi "lanciarlo con l'esempio", il che è anche inutile, poiché richiede ulteriori passaggi e significa che tu CONOSCI già come dovrebbe essere il tipo di oggetto, quindi perché non creare un oggetto e riempirlo in primo luogo?

Qual è l'applicazione per questo?

Non vorrei percorrere questa strada per alcuni motivi.

  • In primo luogo; potrebbe richiedere un sacco di codice di supporto usando reflection e simili per creare il metodo trasparente di cui stai parlando.

  • In secondo luogo, come hai detto, C # è un linguaggio fortemente tipizzato e cose come queste sono state escluse dalle specifiche del linguaggio per un motivo.

  • Terzo, il sovraccarico per farlo non varrebbe la pena. Ricorda che le pagine Web (in particolare le query AJAX) dovrebbero essere molto veloci o vanificare lo scopo. Se vai avanti e spendi il 50% in serializzazione dei tuoi oggetti tra C # e Javascript, allora hai un problema.

La mia soluzione sarebbe quella di creare una classe che incapsula semplicemente un dizionario e che accetta una stringa JSON come argomento ctor. Quindi estendi quella classe per ogni tipo di query JSON che vuoi gestire. Questa sarà una soluzione fortemente tipizzata e più veloce, ma manterrà comunque estensibilità e facilità d'uso. Il rovescio della medaglia è che c'è più codice da scrivere per tipo di richiesta JSON.

:)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top