Convertendo um JToken (ou string) para um determinado tipo
TL; DR Version
Eu tenho um objeto do tipoJToken
(mas também pode ser umstring
) e eu preciso convertê-lo em um tipo contido notype
variável:
Type type = typeof(DateTime); /* can be any other Type like string, ulong etc */
var obj = jsonObject["date_joined"]; /* contains 2012-08-13T06:01:23Z+05:00 */
var result = Some_Way_To_Convert(type, obj);
O de cimaresult
deve ser um objeto DateTime com o valor dado emdate_joined
.
História completa
Estou usando o RestSharp e Json.NET em um projeto do Windows Phone e estou preso ao tentar desserializar respostas JSON de uma API REST.
O que estou realmente tentando realizar é escrever um método genérico que possa mapear facilmente minha resposta JSON em minhas entidades CLR, como você já pode fazer com o RestSharp. O único problema é que a implementação padrão do RestSharp não funciona para mim e falha ao analisar com êxito o JSON, pois a resposta nem sempre retorna todas as propriedades (não retorno campos que sãonull
do servidor REST).
É por isso que decidi usar o Json.NET da Newtonsoft, pois ele tem um mecanismo de desserialização Json muito mais poderoso. Infelizmente, ele não suporta nomes de propriedades / campos fuzzy como RestSharp (ou eu não encontrei nenhum), então ele também não mapeia corretamente para minhas entidades CLR quando eu uso algo como dizerJsonConvert.DeserializeObject<User>(response.Content)
.
Aqui está o meu Json parece (um exemplo, na verdade):
{
"id" : 77239923,
"username" : "UzEE",
"email" : "[email protected]",
"name" : "Uzair Sajid",
"twitter_screen_name" : "UzEE",
"join_date" : "2012-08-13T05:30:23Z05+00",
"timezone" : 5.5,
"access_token" : {
"token" : "nkjanIUI8983nkSj)*#)(kjb@K",
"scope" : [ "read", "write", "bake pies" ],
"expires" : 57723
},
"friends" : [{
"id" : 2347484",
"name" : "Bruce Wayne"
},
{
"id" : 996236,
"name" : "Clark Kent"
}]
}
E aqui está um exemplo das minhas entidades CLR:
class AccessToken
{
public string Token { get; set; }
public int Expires { get; set; }
public string[] Scope { get; set; }
public string Secret { get; set; } /* may not always be returned */
}
class User
{
public ulong Id { get; set; }
public string UserName { get; set; }
public string Email { get; set; }
public string Name { get; set; }
public string TwitterScreenName { get; set; }
public DateTime JoinDate { get; set; }
public float Timezone { get; set; }
public bool IsOnline { get; set; } /* another field that might be blank e.g. */
public AccessToken AccessToken { get; set; }
public List<User> Friends { get; set; }
}
O que eu quero é uma maneira simples de analisar o JSON acima nos objetos CLR fornecidos. Eu olhei em volta do código fonte do RestSharp e vi oJsonDeserializer
código e eu fui capaz de escrever um método de extensão genéricoDeserializeResponse<T>
emJObject
que deve retornar um objeto do tipoT
. O uso pretendido é algo assim:
var user = JObject.Parse(response.Content).DeserializeResponse<User>();
O método acima deve analisar a Resposta Json fornecida a um objeto de entidade Usuário. Aqui está um trecho de código real do que estou fazendo noDeserializeResponse<User>
método de extensão (é baseado no código RestSharp):
public static T DeserializeResponse<T>(this JObject obj) where T : new()
{
T result = new T();
var props = typeof(T).GetProperties().Where(p => p.CanWrite).ToList();
var objectDictionary = obj as IDictionary<string, JToken>;
foreach (var prop in props)
{
var name = prop.Name.GetNameVariants(CultureInfo.CurrentCulture).FirstOrDefault(n => objectDictionary.ContainsKey(n));
var value = name != null ? obj[name] : null;
if (value == null) continue;
var type = prop.PropertyType;
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
{
type = type.GetGenericArguments()[0];
}
// This is a problem. I need a way to convert JToken value into an object of Type type
prop.SetValue(result, ConvertValue(type, value), null);
}
return result;
}
Eu estou supondo que a conversão deve ser uma coisa muito simples de se fazer, já que é uma tarefa trivial. Mas eu tenho procurado por um bom tempo agora e ainda não encontrei uma maneira de fazê-lo através do Json.NET (e, sejamos honestos, a documentação é meio que entender e não tem alguns exemplos).
Qualquer ajuda seria realmente apreciada.