web-dev-qa-db-ja.com

RestSharpのプロパティへの動的な逆シリアル化

Harvest APIを使用していて、エンティティをできるだけ簡単に自動的にマッピングしようとしています。残念ながら、_GET /projects_のようなリクエストを実行すると、次のような結果が生成されます。

_[{
    project: {
        name: "Test"
    }
},
{
    project: {
        name: "Test 2"
}]
_

RestSharpでは、これを直接行うことはできません。

_client.Execute<List<Project>>(request)
_

Projectというプロパティを探すためです。そのため、そのプロパティを持つ別のクラスを作成し、次のように呼び出す必要があります。

_client.Execute<List<ProjectContainer>>(request)
_

すべてのエンティティに対して「コンテナ」クラスを作成したくないので、すべてのクラスで使用できる1つのクラスを作成するための賢い解決策を見つけました。

_public class ListContainer<T> where T : IHarvestEntity
{
    public T Item { get; set; }
}
_

ただし、もちろん、デシリアライザはエンティティ名(または「プロジェクト」)をプロパティItemにマップする必要があることを理解していません。 Restsharpのドキュメントでは、[DeserializeAs(Name = "CustomProperty")]を使用して、このプロパティにマップするフィールドをデシリアライザに指示できることがわかりました。ただし、属性は定数のみを許可します。つまり、次のことはできません。

_[DeserializeAs(Name = typeof(T).FullName)]
public T Item { get; set; }
_

誰かがこれに対する賢い解決策を知っていますか?それで、10の異なるコンテナークラスを作成する必要はありませんか?

27
Chris

Jsonに相当するXPathを使用することをお勧めします。 Json.NETを使用すると、文字列を parse して動的オブジェクトを作成できます。

SelectToken を使用すると、値をクエリしたり、 Linq を使用したりできます。

コードは次のようになります(テストしていません)。

// execute the request
RestResponse response = client.Execute(request);
var content = response.Content; // raw content as string

JObject o = JObject.Parse(content);

IList<string> projectNames = o.SelectToken("project").Select(s => (string)s.name).ToList();

パスをコーディングしたり、パスを構成したりできます。

---編集---

以下は、json文字列をプロジェクトのリストに変換してテストした例です。

var projects = JArray.Parse(response.Content).Select(r => new Project(r["project"]["name"].Value<string>())).ToList();
8

本当にシンプルに保つには、List<dynamic>し、ワンライナーで名前でプロパティにアクセスします。

var names = client.Execute<List<dynamic>>(request).Data.Select(
              item => item["project"]["name"]).ToList(); // list of names

これで十分でない場合は、独自のマッパーを即興で作成し、たとえば、 Projectインスタンス:

var projects = client.Execute<List<dynamic>>(request).Data.Select(
                 item => Map<Project>(item)).ToList(); // list of Project instances

Mapメソッドは次のようになります

public T Map<T>(dynamic item) where T : class
{
    // inline for clarity
    var mappings = new Dictionary<Type,Func<dynamic,object>>
        {
            { typeof(Project), map => new Project(map["project"]["name"]) }
        };

    return (T)mappings[typeof(T)].Invoke(item);
}

与えられたProjectは次のように定義されます

public class Project
{
    public Project(string name)
    {
        Name = name;
    }
    public string Name { get; set; }
}
3
Mikko Viitala