Pergunta

Desde Inicializadores de objeto são muito semelhantes a JSON, e agora existem tipos anônimos em .NET. Seria legal ser capaz de tomar uma string, como JSON, e criar um objeto anônimo que representa a string JSON.

Utilize Inicializadores de objeto para criar um tipo anônimo:

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

Seria fantástico se você poderia passar em uma representação de string do código inicializador de objeto (de preferência algo como JSON) para criar uma instância de um tipo anônimo com esses dados.

Eu não sei se é possível, uma vez que C # não é dinâmico, e o compilador realmente converte o objeto Initializer um d Anonymous Tipo em código fortemente tipado que pode ser executado. Isto é explicado em este artigo.

Talvez funcionalidade para tirar JSON e criar uma chave / valor do dicionário com ele iria trabalhar melhor.

Eu sei que você pode serializar / desserializador um objeto para JSON em .NET, mas o que eu sou olhar para é uma maneira de criar um objeto que é essencialmente vagamente digitado, da mesma forma como funciona JavaScript.

Alguém sabe a melhor solução para fazer isso em .NET?

UPDATE: Too esclarecer o contexto de por que eu estou pedindo isso ... Eu estava pensando em como C # pode melhor apoiar JSON no nível da linguagem (possivelmente) e eu estava tentando pensar em maneiras que isso poderia ser feito hoje , por razões conceituais. Então, eu pensei que eu ia postar aqui para iniciar uma discussão.

Foi útil?

Solução

Existem idiomas para .NET que têm pato digitação mas não é possível com C # usando Dot.Notation desde C # requer que todas as referências membros são resolvidos em tempo de compilação. Se você quiser usar o Dot.Notation, você ainda tem que definir um lugar de classe com as propriedades necessárias, e usar qualquer método que deseja instanciar a classe a partir dos dados JSON. Pré-definindo uma classe não tem benefícios como tipagem forte, suporte IDE incluindo intellisense e não se preocupar com erros de ortografia. Você ainda pode usar 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

Outras dicas

Você deve verificar se o JSON.net projeto:

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

Você é basicamente falando sobre a capacidade de hidratar um objeto JSON, que isso vai fazer. Não vai fazer os tipos anônimos, mas talvez ele vai te perto o suficiente.

Eu escrevi um método relativamente curto que irá analisar JSON e retornar um nome / valor dicionário que pode ser acessado de forma semelhante ao objeto real em JavaScript.

Aqui está um uso de amostra do abaixo método:

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

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

E, aqui está o código para o 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;
}

Eu sei que este método pode ser um pouco áspero, e poderia provavelmente ser otimizado um pouco, mas é o primeiro esboço e ele simplesmente funciona.

Além disso, antes de reclamar não usando expressões regulares, tenha em mente que nem todos realmente entende expressões regulares, e escrevê-lo dessa forma tornaria mais difícil para os outros para corrigir, se necessário. Além disso, atualmente eu não sei expressão regular muito bem, e corda de análise foi apenas mais fácil.

Você não pode retornar um tipo anônimo de um método **, portanto, um "reidratadas" existência de tipo anônimo seria limitado ao método em que é reidratado. Tipo de inútil.

** Você pode devolvê-lo como um objeto (que requer reflexão para acessar suas propriedades - yeech) ou você pode "lançá-lo pelo exemplo", que é inútil, bem como, uma vez que toma medidas extras e isso significa que você já saber que tipo do objeto deve ser parecida, então porque não basta criar um objeto e preenchê-lo em primeiro lugar?

O que é a aplicação para isso?

Eu não iria por esse caminho por alguns motivos.

  • Em primeiro lugar; ele pode exigir um monte de código de suporte usando a reflexão e tal para criar o método transparente que você está falando.

  • Em segundo lugar, como você disse, C # é uma linguagem fortemente digitado e coisas semelhantes a estas foram deixados de fora da especificação de linguagem por uma razão.

  • Em terceiro lugar, a sobrecarga para fazer isso não seria pena. Lembre-se que as páginas web (especialmente consultas Ajax) deve ser muito rápido ou ele derrota o propósito. Se você vá em frente e gastar 50% a serialização de seus objetos entre C # e Javascript, então você tem um problema.

A minha solução seria criar uma classe que apenas encapsula um dicionário e que leva uma string JSON como um argumento ctor. Em seguida, basta estender essa classe para cada tipo de JSON consulta que você deseja manipular. Esta será uma solução fortemente digitado e mais rápido, mas ainda manter a extensibilidade e facilidade de uso. A desvantagem é que há mais código para escrever por tipo de solicitação JSON.

:)

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top