web-dev-qa-db-ja.com

クエリ文字列で使用するクラスからJSONプロパティ名のリストを取得する

JSON.netがシリアル化されたJSON文字列からデータをバインドするために使用するC#モデルクラスがある場合、そのクラスからクエリ文字列を作成して最初のリクエストを行う方法はありますか?

モデルクラスの例:

public class model
{
   [JsonProperty(PropertyName = "id")]
   public long ID { get; set; }
   [JsonProperty(PropertyName = "some_string")]
   public string SomeString {get; set;} 
}

クエリ文字列の例:

baseUrl + uri + "&fields=id,some_string" + token

したがって、私がやろうとしていることの本質は、モデルオブジェクトから「id」と「some_string」の両方を収集して、「&fields」引数を動的に作成できるようにすることです。ありがとう!

15
CostelloNicho

@リー・シェパーソンは正しい考えを持っています。ただし、LINQを使用すると、少ないコードでそれを実行できます。次のようなヘルパーメソッドを作成します。

using System.Linq;
using System.Reflection;
using Newtonsoft.Json;
...

public static string GetFields(Type modelType)
{
    return string.Join(",",
        modelType.GetProperties()
                 .Select(p => p.GetCustomAttribute<JsonPropertyAttribute>())
                 .Select(jp => jp.PropertyName));
}

次のように使用できます。

var fields = "&fields=" + GetFields(typeof(model));

[〜#〜]編集[〜#〜]

.Net Frameworkの3.5バージョンで実行していて、汎用のGetCustomAttribute<T>メソッドを使用できない場合は、汎用ではないGetCustomAttributes()でも同じことができます。代わりに、メソッドをSelectManyおよびCast<T>で使用します。

    return string.Join(",",
        modelType.GetProperties()
                 .SelectMany(p => p.GetCustomAttributes(typeof(JsonPropertyAttribute))
                                   .Cast<JsonPropertyAttribute>())
                 .Select(jp => jp.PropertyName)
                 .ToArray());
22
Brian Rogers

リフレクションを使用してこれを行うことができます。これは一般的な考え方です:

using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System.Reflection;

namespace ConsoleApplication8
{
    public class model
    {
        [JsonProperty(PropertyName = "id")]
        public long ID { get; set; }

        [JsonProperty(PropertyName = "some_string")]
        public string SomeString { get; set; }
    }

    internal class Program
    {
        private static void Main(string[] args)
        {
            var model = new model();

            var result = string.Empty;

            PropertyInfo[] props = typeof(model).GetProperties();
            foreach (PropertyInfo prop in props)
            {
                foreach (object attr in prop.GetCustomAttributes(true))
                {
                    result += (attr as JsonPropertyAttribute).PropertyName;
                }
            }
        }
    }
}
6

モデルが[JsonProperty(PropertyName = "XXX")]属性で部分的にのみ注釈されている場合、または データコントラクト属性 で注釈されている場合、または 無視された プロパティがある場合は、Jsonを使用できます.NET独自の contract resolver を使用して、シリアル化されたプロパティ名のリストを取得します。まず、次の拡張メソッドを紹介します。

public static class JsonExtensions
{
    public static string [] PropertyNames(this IContractResolver resolver, Type type)
    {
        if (resolver == null || type == null)
            throw new ArgumentNullException();
        var contract = resolver.ResolveContract(type) as JsonObjectContract;
        if (contract == null)
            return new string[0];
        return contract.Properties.Where(p => !p.Ignored).Select(p => p.PropertyName).ToArray();
    }
}

次に、次のようにします。

// Allocate the relevant contract resolver. 
// Options are CamelCasePropertyNamesContractResolver() or DefaultContractResolver().
IContractResolver resolver = new DefaultContractResolver(); 

// Get properties
var propertyNames = resolver.PropertyNames(typeof(model));
var fields = "&fields=" + String.Join(",", propertyNames);

resolverの場合 CamelCasePropertyNamesContractResolver プロパティ名をキャメルでカバーしている場合(これはASP.NET Core Web APIが行います デフォルトで );それ以外の場合は DefaultContractResolver を使用します。

サンプル fiddle

4
dbc

Null例外問題を解決する@Brian Rogersソリューションの小さなバリエーション:

IEnumerable<string> props = typeof(T).GetProperties()
                                     .Select(p => p.GetCustomAttribute<JsonPropertyAttribute>())
                                     .Where(jp => jp != null)
                                     .Select(jp => jp.PropertyName);

string propsList = string.Join(',', props);
0
Rafael Jiménez