2012-08-13 18 views
47

टी एल के लिए एक JToken (या स्ट्रिंग) परिवर्तित; डॉ संस्करणएक दिया प्रकार

मैं प्रकार JToken की एक वस्तु है (लेकिन यह भी एक string हो सकता है) और मैं इसे एक प्रकार में निहित में परिवर्तित करने की जरूरत है type चर: result ऊपर

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); 

date_joined में दिए गए मूल्य के साथ एक दिनांक समय वस्तु होना चाहिए।

पूर्ण स्टोरी

मैं एक विंडोज फोन परियोजना में दोनों RestSharp और Json.NET उपयोग कर रहा हूँ और मैं अटक कर रहा हूँ एक REST API से JSON प्रतिक्रियाओं deserialize की कोशिश करते हुए।

जो मैं वास्तव में पूरा करने की कोशिश कर रहा हूं वह एक सामान्य विधि लिखना है जो मेरी सीएलआर इकाइयों में आसानी से मेरे JSON प्रतिक्रिया को मैप कर सकता है, जैसा कि आप पहले से ही RestSharp के साथ कर सकते हैं। एकमात्र समस्या यह है कि डिफ़ॉल्ट RestSharp कार्यान्वयन मेरे लिए काम नहीं कर रहा है और यह JSON को सफलतापूर्वक पार्स करने में विफल रहता है क्योंकि प्रतिक्रिया हमेशा सभी गुणों को वापस नहीं करती है (मैं उन फ़ील्ड को वापस नहीं करता जो REST सर्वर से null हैं)।

यही कारण है कि मैंने न्यूटॉन्सॉफ्ट के जेसन.NET का उपयोग करने का फैसला किया क्योंकि इसमें एक अधिक शक्तिशाली जेसन deserializing इंजन है। दुर्भाग्यवश, यह RestSharp (या मुझे कोई नहीं मिला) जैसी अस्पष्ट संपत्ति/फ़ील्ड नामों का समर्थन नहीं करता है, इसलिए जब मैं JsonConvert.DeserializeObject<User>(response.Content) कहता हूं तो यह मेरी सीएलआर इकाइयों को सही ढंग से मैप नहीं करता है।

{ 
    "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)*#)([email protected]", 
     "scope" : [ "read", "write", "bake pies" ], 
     "expires" : 57723 
    }, 
    "friends" : [{ 
     "id" : 2347484", 
     "name" : "Bruce Wayne" 
    }, 
    { 
     "id" : 996236, 
     "name" : "Clark Kent" 
    }] 
} 

और यहाँ मेरी 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; } 
} 

क्या मैं चाहता हूँ ऊपर पार्स करने के लिए एक आसान तरीका है

यहाँ मेरी Json (एक वास्तव में उदाहरण) कैसा दिखता है दिए गए सीएलआर वस्तुओं में JSON। मैंने RestSharp स्रोत कोड के चारों ओर देखा है और JsonDeserializer कोड देखा है और मैं JObject पर एक सामान्य विस्तार विधि DeserializeResponse<T> लिखने में सक्षम हूं जो T प्रकार का ऑब्जेक्ट लौटाएगा। इच्छित उपयोग कुछ ऐसा है:

var user = JObject.Parse(response.Content).DeserializeResponse<User>(); 

उपरोक्त विधि को किसी उपयोगकर्ता इकाई ऑब्जेक्ट को दिए गए जेसन प्रतिक्रिया को पार्स करना चाहिए। यहाँ मैं DeserializeResponse<User> विस्तार विधि में क्या कर रहा का एक वास्तविक कोड का टुकड़ा है (इसके 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; 
} 

मेरा अनुमान है कि है कि रूपांतरण इसकी एक छोटी सी के बाद से ऐसा करने के लिए एक बहुत सरल बात होना चाहिए कार्य। लेकिन मैं थोड़ी देर के लिए खोज कर रहा हूं और अभी भी Json.NET के माध्यम से ऐसा करने का कोई तरीका नहीं मिला है (और ईमानदार होने दें, दस्तावेज कुछ उदाहरणों को समझने और कम करने के बावजूद है)।

किसी भी मदद की वास्तव में सराहना की जाएगी।

+0

किसी भी मदद के लिए यहाँ? यह दूसरी बार है जब मैंने एसओ पर कोई सवाल पूछा है और फिर भी इसका जवाब कभी नहीं मिला:/ –

+0

http://stackoverflow.com/questions/9589218/get-value-from-jtoken-that-may-not-exist- सर्वोत्तम प्रथाओं – Guillaume

+0

@ गुइलियम धन्यवाद। पोस्टिंग से पहले मैंने पहले ही पढ़ा था। समस्या यह है कि मैं एक पार्सर लिख रहा हूं जो किसी भी मूल्य को संभालने में सक्षम होना चाहिए ताकि एक आसान 'jToken.value ()' काम नहीं करेगा क्योंकि मुझे नहीं पता कि यह एक 'डबल' होगा। मैं हाथ से पहले के प्रकार को नहीं जानता। –

उत्तर

90

अब एक ToObject विधि है।

var obj = jsonObject["date_joined"]; 
var result = obj.ToObject<DateTime>(); 

यह भी किसी भी जटिल प्रकार के साथ काम करता है, और JsonPropertyAttribute का पालन नियम

var result = obj.ToObject<MyClass>(); 

public class MyClass 
{ 
    [JsonProperty("date_field")] 
    public DateTime MyDate {get;set;} 
} 
+2

+1 यह 'टॉस्ट्रिंग()' को कॉल करने और फिर इसे deserializing करने से पहले करने का एक बहुत साफ तरीका है। मुझे 100% यकीन नहीं है कि बोनट के नीचे क्या अंतर है, लेकिन यह बहुत अच्छा है। – theyetiman

+2

यदि आप डिज़ाइन समय के रूप में टाइप नहीं जानते हैं, तो ToObject() का ओवरलोडेड संस्करण है जो पैरामीटर के रूप में टाइप करता है। मैं सहमत हूँ। यह सबसे साफ समाधान है। यह वास्तव में "जवाब" होना चाहिए। –

22
System.Convert.ChangeType(jtoken.ToString(), targetType); 

या

JsonConvert.DeserializeObject(jtoken.ToString(), targetType); 

--EDIT--

Uzair, यहां एक संपूर्ण उदाहरण केवल आपके दिखाने के लिए वे काम करते हैं

string json = @"{ 
     ""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)*#)([email protected]"", 
      ""scope"" : [ ""read"", ""write"", ""bake pies"" ], 
      ""expires"" : 57723 
     }, 
     ""friends"" : [{ 
      ""id"" : 2347484, 
      ""name"" : ""Bruce Wayne"" 
     }, 
     { 
      ""id"" : 996236, 
      ""name"" : ""Clark Kent"" 
     }] 
    }"; 

var obj = (JObject)JsonConvert.DeserializeObject(json); 
Type type = typeof(int); 
var i1 = System.Convert.ChangeType(obj["id"].ToString(), type); 
var i2 = JsonConvert.DeserializeObject(obj["id"].ToString(), type); 
+3

इनमें से दोनों काम नहीं करते हैं। 'System.Convert.ChangeType()' को तीसरे 'IFormatProvider' पैरामीटर की आवश्यकता है। और 'JsonConvert.DeserializeObject()' एक अपवाद फेंकता है: "अनपेक्षित चरित्र का सामना करते हुए मूल्य पार्सिंग: यू पथ", रेखा 0, स्थिति 0. " –

+0

@UzairSajid मैंने पोस्ट करने से पहले उन कोडों का परीक्षण किया। 'IFormatProvider' वैकल्पिक है। दूसरे भाग के लिए। यदि आप अपना कोड + डेटा पोस्ट करते हैं तो मैं इस पर काम करने की कोशिश कर सकता हूं। –

+2

यह ठीक तरह से काम नहीं करता जैसा आपने कहा था (वास्तव में 'System.Convert.ChangeType()' के लिए विधि हस्ताक्षर विंडोज फोन पर अलग है) क्योंकि इसे अनिवार्य तीसरे 'IFormatProvider' पैरामीटर की आवश्यकता है। लेकिन मैं इसे 'शून्य' को तीसरे पैरामीटर के रूप में पास करके और कुछ किनारे के मामलों को स्पष्ट रूप से संभालने में कामयाब रहा (जैसे '1' '' '' '' '' '' '' '' '' '' '' '' '' '' '' ') अभी के लिए। देखेंगे कि यह अभी भी लंबी अवधि में काम करता है या नहीं। –

1
var i2 = JsonConvert.DeserializeObject(obj["id"].ToString(), type); 

फेंकता है एक पार्सिंग अपवाद डी पहले तर्क के आसपास गायब उद्धरण के कारण (मुझे लगता है)। मुझे उद्धरण जोड़कर काम करने के लिए मिला:

var i2 = JsonConvert.DeserializeObject("\"" + obj["id"].ToString() + "\"", type); 
0

मैं अपने वेबएपीआई के लिए विधि नीचे का उपयोग कर परिवर्तित करने में सक्षम था:

[HttpPost] 
public HttpResponseMessage Post(dynamic item) // Passing parameter as dynamic 
{ 
JArray itemArray = item["Region"]; // You need to add JSON.NET library 
JObject obj = itemArray[0] as JObject; // Converting from JArray to JObject 
Region objRegion = obj.ToObject<Region>(); // Converting to Region object 
}