9

オブジェクト初期化子は JSON に非常に似ているため、.NET には匿名型があります。JSON などの文字列を取得して、JSON 文字列を表す匿名オブジェクトを作成できると便利です。

オブジェクト初期化子を使用して、匿名型を作成します。

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

オブジェクト初期化コード (できれば JSON のようなもの) の文字列表現を渡して、そのデータを使用して匿名型のインスタンスを作成できれば素晴らしいことです。

C# は動的ではなく、コンパイラは実際にオブジェクト初期化子と匿名型を実行可能な厳密に型指定されたコードに変換するため、それが可能かどうかはわかりません。これについては、この記事で説明します。

おそらく、JSON を使用してキー/値ディクショナリを作成する機能が最適です。

.NET でオブジェクトを JSON にシリアル化/逆シリアル化できることは知っていますが、私が探しているのは、JavaScript のしくみと同様に、本質的に緩く型付けされたオブジェクトを作成する方法です。

.NETでこれを行うための最良の解決策を知っている人はいますか?

更新:なぜ私がこれを求めているのかという文脈を明確にしすぎています...私は、C#が言語レベルで(おそらく)JSONをより適切にサポートする方法を考えていました。理由。そこで、ここに投稿して議論を始めようと思いました。

4

5 に答える 5

8

ダックタイピングを持つ .NET 用の言語がありますが、C# ではすべてのメンバー参照がコンパイル時に解決される必要があるため、Dot.Notation を使用する C# では不可能です。Dot.Notation を使用する場合でも、必要なプロパティを持つクラスをどこかに定義し、必要なメソッドを使用して JSON データからクラスをインスタンス化する必要があります。クラスを事前定義することには、強力な型付け、インテリセンスを含む IDE サポート、スペルミスの心配がないなどの利点があります引き続き匿名型を使用できます。

 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
于 2008-10-14T02:13:29.757 に答える
5

JSON.netプロジェクトを確認してください。

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

あなたは基本的に、JSON からオブジェクトをハイドレートする機能について話しています。匿名型は実行しませんが、十分に近づけることができるでしょう。

于 2008-10-14T02:26:12.977 に答える
4

JSON を解析し、JavaScript の実際のオブジェクトと同様にアクセスできる名前/値ディクショナリを返す比較的短いメソッドを作成しました。

以下のメソッドの使用例を次に示します。

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

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

そして、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;
}

この方法は少し大雑把かもしれませんが、おそらくかなり最適化される可能性がありますが、これは最初のドラフトであり、うまく機能します。

また、正規表現を使用していないことに不満を言う前に、誰もが正規表現を本当に理解しているわけではないことを覚えておいてください。そのように書くと、必要に応じて他の人が修正するのが難しくなります. また、私は現在、正規表現についてあまりよく知りません。文字列の解析は簡単でした。

于 2008-10-14T03:24:51.283 に答える
1

メソッド**から匿名型を返すことはできないため、「再水和された」匿名型の存在は、再水和されたメソッドに限定されます。ちょっと無意味。

** オブジェクトとして返すこともできます (そのプロパティにアクセスするにはリフレクションが必要です--yeech)、または「例によってキャストする」こともできます。オブジェクトの型は次のように見えるはずなので、最初にオブジェクトを作成して埋めてみませんか?

于 2008-10-14T03:24:13.593 に答える
0

これのアプリケーションは何ですか?

いくつかの理由で、私はこの道をたどりませんでした。

  • 初め; あなたが話している透過的なメソッドを作成するには、リフレクションなどを使用して多くのサポートコードが必要になる場合があります。

  • 第二に、あなたが言ったように、C# は厳密に型指定された言語であり、これらのようなものは理由により言語仕様から除外されました。

  • 第 3 に、これを行うためのオーバーヘッドはそれほど価値がありません。Web ページ (特に AJAX クエリ) は非常に高速でなければならないことに注意してください。C# と Javascript の間でオブジェクトのシリアル化に 50% を費やすと、問題が発生します。

私の解決策は、辞書をカプセル化するだけで、JSON 文字列を ctor 引数として受け取るクラスを作成することです。次に、処理する JSON クエリの種類ごとにそのクラスを拡張します。これは、厳密に型指定されたより高速なソリューションになりますが、拡張性と使いやすさは維持されます。欠点は、JSON リクエストのタイプごとに記述するコードが増えることです。

:)

于 2008-10-14T01:49:41.910 に答える