2017-09-20 15 views
4

私はまだかなりプログラミングが新しく、未処理のJSON文字列を取り込み、JSONをオブジェクトに解析して処理用のハンドラに渡すWebHookコンシューマを作成する任務があります。 JSONは次のようで来ている:タイプを知らなくても汎用オブジェクトを返す?

public class WebHookModel<T> where T : class, new() 
{ 
    [JsonProperty(PropertyName = "id")] 
    public string Id { get; set; } 

    [JsonProperty(PropertyName = "created_at")] 
    public DateTime CreatedAt { get; set; } 

    [JsonProperty(PropertyName = "type")] 
    public string Type { get; set; } 

    [JsonProperty(PropertyName = "object")] 
    public T Object { get; set; } 

    [JsonIgnore] 
    public string WebHookAction 
    { 
     get 
     { 
      return string.IsNullOrEmpty(Type) ? string.Empty : Type.Split('.').Last(); 
     } 
    } 
} 

次に作成:

{ 
    "id":"1", 
    "created_at":"2017-09-19T20:41:23.093Z", 
    "type":"person.created", 
    "object":{ 
     "id":"person1", 
     "created_at":"2017-09-19T20:41:23.076Z", 
     "updated_at":"2017-09-19T20:41:23.076Z", 
     "firstname":"First", 
     ... 
    } 
} 

私はこれがジェネリックを使用する絶好の機会だと思ったし、次のように私のクラスを構築しましたので、内部オブジェクトは、任意のオブジェクトにすることができます次のインターフェイス:

public interface IWebHookModelFactory<T> where T : class, new() 
{ 
    WebHookModel<T> GetWebHookModel(string type, string jsonPayload); 
} 

は、私が理解するために失敗していますが、どのように私はタイプがコンパイル時に何であるか知らなくてもファクトリクラスを実装することが出来るのですか?

モデルをちょっと見て、抽象的なTオブジェクトを持つ抽象クラスに変更し、派生クラスで定義できるようにしました。

public abstract class WebHookModel<T> where T : class, new() 
{ 
    [JsonProperty(PropertyName = "id")] 
    public string Id { get; set; } 

    [JsonProperty(PropertyName = "created_at")] 
    public DateTime CreatedAt { get; set; } 

    [JsonProperty(PropertyName = "type")] 
    public string Type { get; set; } 

    [JsonProperty(PropertyName = "object")] 
    public abstract T Object { get; set; } 

    [JsonIgnore] 
    public string WebHookAction 
    { 
     get 
     { 
      return string.IsNullOrEmpty(Type) ? string.Empty : Type.Split('.').Last(); 
     } 
    } 
} 

public PersonWebHookModel : WebHookModel<Person> 
{ 
    public override Person Object { get; set; } 
} 

しかし、実行時に型がわからないインターフェイスを実装しようとするのと同じ問題が発生します。私がオンラインで見つけたことから、これは共分散の例ですが、この問題を解決する方法を説明する記事は見つかりませんでした。ジェネリックスをスキップして大文字の case文を作成するのが最善でしょうか?

public interface IWebHookFactory<TModel, TJsonObject> 
    where TJsonObject : class, new() 
    where TModel : WebHookModel<TJsonObject> 
{ 
    TModel GetWebHookModel(string type, string jsonPayload); 
} 

それは私が私が私のサービスに渡しているどのモデルに基づいて個々のハンドラを定義することができますので、私は抽象クラスのアプローチを使用するビットの部分です。解決のための

public interface IWebHookService<TModel, TJsonObject> 
    where TJsonObject : class, new() 
    where TModel : WebHookModel<TJsonObject> 
{ 
    void CompleteAction(TModel webHookModel); 
} 

public abstract class BaseWebhookService<TModel, TJsonObject> : IWebHookService<TModel, TJsonObject> 
     where TJsonObject : class, new() 
     where TModel : WebHookModel<TJsonObject> 
{ 
    public void CompleteAction(TModel webHookModel) 
    { 
     var self = this.GetType(); 
     var bitWise = System.Reflection.BindingFlags.IgnoreCase 
         | System.Reflection.BindingFlags.Instance 
         | System.Reflection.BindingFlags.NonPublic; 

     var methodToCall = self.GetMethod(jsonObject.WebHookAction, bitWise); 
     methodToCall.Invoke(this, new[] { jsonObject }); 
    } 

    protected abstract void Created(TModel webHookObject); 

    protected abstract void Updated(TModel webHookObject); 

    protected abstract void Destroyed(TModel webHookObject); 
} 

public class PersonWebHookService : BaseWebHookService<PersonWebHookModel, Person> 
{ 
    protected override void Created(PersonWebHookModel webHookModel) 
    { 
     throw new NotImplementedException(); 
    } 

    protected override void Updated(PersonWebHookModel webHookModel) 
    { 
     throw new NotImplementedException(); 
    } 

    protected override void Destroyed(PersonWebHookModel webHookModel) 
    { 
     throw new NotImplementedException(); 
    } 
} 
+1

た場合インフォーマットのみあなたが 'T'を持っているイオンは実行時の型情報(' Type'、名前、またはあなたが持っているもの)であり、ジェネリックを使わないなら、それは仕事のための正しいツールではありません。あなたは無意味な 'WebHookModel 'で終わるでしょう。インターフェイスの非汎用バージョンを使用するだけです。 – InBetween

+0

これらのオブジェクトで正確に何が行われていますか?下流でどのように処理されるのですか?それらのすべてに対応するハンドラが1つありますか、またはそれぞれのハンドラがありますか? –

+0

WebHookオブジェクトが入ってくるごとに、これまでに10個見つかりました。別の方法で処理する必要があります。 BaseWebHookServiceとPersonWebHookServiceは、各オブジェクトの処理方法の例です。 APIドキュメントの規約には、object.action(作成、更新、または破棄されるアクション)があります。 BaseWebHookServiceは、渡されるWebHookModelに基づいて、使用する派生サービスを認識します。 – bschreck

答えて

2

キーポイント: 1.どこかにいくつかの仮想呼び出しが必要です。 2.何とかJSONペイロードの型タグから実際のC#クラスにマップする必要があります。
IE、 "person.created"、 " - Person"。
シリアル化形式を制御すると、JSON.Netは独自のタイプタグを挿入してこれを実行できます。 ... だから、マッピングを含むように辞書のようなものが必要になります

あなたの定義を仮定するとのようである:。

abstract class WebhookPayload // Note this base class is not generic! 
{ 
    // Common base properties here 

    public abstract void DoWork(); 
} 

abstract class PersonPayload : WebhookPayload 
{ 
    public override void DoWork() 
    { 
     // your derived impl here 
    } 
} 

そして、あなたは次のようにデシリアライズすることができます:

static Dictionary<string, Type> _map = new Dictionary<string, Type> 
    { 
     { "person.created", typeof(PersonPayload)} 
    }; // Add more entries here 

    public static WebhookPayload Deserialize(string json) 
    { 
     // 1. only parse once! 
     var jobj = JObject.Parse(json); 

     // 2. get the c# type 
     var strType = jobj["type"].ToString(); 

     Type type; 
     if (!_map.TryGetValue(strType, out type)) 
     { 
      // Error! Unrecognized type 
     } 

     // 3. Now deserialize 
     var obj = (WebhookPayload) jobj.ToObject(type); 
     return obj; 
    } 
+0

したがって、ファクトリに具体的な実装が必要であるため、 'Dictionary > factoryMapper'のようなマッパー辞書を作成する方法はありませんか?コンクリートクラス(PersonWebHookModel)が返されるので、なぜ私は 'IWebHookFactory 'を実装することができないのか分かりません。おそらく、ジェネリックを削除し、WebHookModelを基本クラスとして使用する必要があります。 – bschreck

+0

右。 'Dictionary > factoryMapper'は未解決のジェネリックTJsonを持っているので、これを持つことはできません。だからここでのトリックは、a)仮想を持つ非ジェネリックな基底クラスを持つことです。 b)派生クラスに何かジェネリックを持つ。その実装で仮想を実装し、汎用プロパティを活用することができます。 –

関連する問題