[英]Returning a generic object without knowing the type?
我仍然是編程方面的新手,並且負責創建一個接收原始JSON字符串的WebHook使用者,將JSON解析為一個對象,該對象將被傳遞到處理程序中進行處理。 JSON就像這樣:
{
"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 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();
}
}
}
然后創建以下界面:
public interface IWebHookModelFactory<T> where T : class, new()
{
WebHookModel<T> GetWebHookModel(string type, string jsonPayload);
}
我無法理解的是如何在不知道編譯時類型是什么的情況下實現Factory類?
稍微使用Model,我將它改為帶有抽象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; }
}
但我仍然遇到同樣的問題,試圖實現一個我不知道運行時類型的接口。 從我在網上找到的,這是一個協方差的例子,但我沒有找到任何解釋如何解決這個問題的文章。 是否最好跳過泛型並創建一個大規模的案例陳述?
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。某處需要進行一些虛擬呼叫。 2.不知何故,您需要從JSON有效負載中的類型標記映射到實際的C#類。
IE,“person.created”,“ - >'Person'。
如果您控制序列化格式,JSON.Net可以注入自己的類型標記並為您執行此操作。 假設你不能走那條路......所以你需要像Dictionary這樣的東西來包含映射。
假設您的定義如下:
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;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.