-1

I have this code:

var jsonResponse = response.Content.ReadAsStringAsync().Result;
            List<TranslationResult> a  = JsonConvert.DeserializeObject< List<TranslationResult>>(jsonResponse);
var t0 = (a[0] != null) ? a[0] : null;
var t1 = (t0 != null) ? t0.Translations[0] : null;
var t2 = (t1 != null) ? t1.DisplayTarget : null;
var p2 = (t1 != null) ? t1.PosTag : null;

public class TranslationResult
{
    public string DisplaySource { get; set; }
    public Translation[] Translations { get; set; }
}

public class Translation
{
    public string DisplayTarget { get; set; }
    public string PosTag { get; set; }
}

The code I am using with all the null tests looks messy and I would like to clean this up. Can anyone suggest a way that I can do this or perhaps suggest a way using LINQ if that's possible. Note that I only need the DisplayTarget and PosTag details.

Roxana Sh
  • 294
  • 1
  • 3
  • 14
Alan2
  • 23,493
  • 79
  • 256
  • 450
  • Not related to your question, but please see https://blog.stephencleary.com/2012/07/dont-block-on-async-code.html regarding the `.ReadAsStringAsync().Result`. – GSerg Sep 01 '19 at 08:39
  • Possible duplicate of [C# elegant way to check if a property's property is null](https://stackoverflow.com/questions/3468250/c-sharp-elegant-way-to-check-if-a-propertys-property-is-null) – GSerg Sep 01 '19 at 08:42

4 Answers4

3

You can only use LINQ to get the translation results and translations within. You will still have to unpack DisplayTarget and PosTag.

List<TranslationResult> a = JsonConvert.DeserializeObject<List<TranslationResult>>(jsonResponse);
var firstTranslation = a.FirstOrDefault()?.Translations?.FirstOrDefault();
var displayTarget = firstTranslation?.DisplayTarget;
var posTag = firstTranslation?.PosTag;

Also, you could use C# 7.0 tuples to unpack multiple values in one go.

List<TranslationResult> a = JsonConvert.DeserializeObject<List<TranslationResult>>(jsonResponse);
var firstTranslation = a.FirstOrDefault()?.Translations?.FirstOrDefault();
var (displayTarget, posTag) = (firstTranslation?.DisplayTarget, firstTranslation?.PosTag);

If you would like to use all the values, not just first like in your example, you can use LINQ as following:

List<TranslationResult> results = JsonConvert.DeserializeObject<List<TranslationResult>>(jsonResponse);
var translations = (results ?? Enumerable.Empty<TranslationResult>())
            .Select(x => x.Translations)
            .Where(x => x != null)
            .SelectMany(x => x)
            .Where(x => x != null)
            .Select(x => (x.DisplayTarget, x.PosTag));
foreach (var (displayTarget, posTag) in translations)
{
    // do something with displayTarget and posTag
}
pneuma
  • 917
  • 5
  • 10
  • This only returns 1 result from a list with n results and discards the remaining n-1 results for both collections (inner and outer). – BionicCode Sep 01 '19 at 09:33
  • @BionicCode Thanks! Expanded on it. Got confused by the question, to me, it seemed like only the first value is needed. – pneuma Sep 01 '19 at 09:41
2

Here is an example using Linq and named tuples:

List<TranslationResult> a = JsonConvert.DeserializeObject<List<TranslationResult>>(jsonResponse);

IEnumerable<(string DisplayTarget, string PosTag)> tuples = 
  a.Where(t0 => t0?.Translations ?? false)
    .SelectMany(
      t0 => t0.Translations.Select(
        t1 => (DisplayTarget: t1?.DisplayTarget ?? string.Empty, PosTag: t1?.PosTag ?? string.Empty)));

// Iterate over the result of named tuples
foreach ((string DisplayTarget, string PosTag) tuple : tuples)
{
  // Values are string.Empty when they returned null from deserialization
  var displayTarget = tuple.DisplayTarget;
  var posTag = tuple.PosTag;
}
BionicCode
  • 1
  • 4
  • 28
  • 44
1
var t0 = (a[0] != null) ? a[0] : null;

This can be changed to

var t0 = a[0];

because the result is the same. And

var t1 = (t0 != null) ? t0.Translations[0] : null;
var t2 = (t1 != null) ? t1.DisplayTarget : null;
var p2 = (t1 != null) ? t1.PosTag : null;

can be changed to

var t1 = t0?.Translations[0];
var t2 = t1?.DisplayTarget;
var p2 = t1?.PosTag;

Using the null condition operator is a short form for the "if not null return this otherwise return null" check.

Volkmar Rigo
  • 1,158
  • 18
  • 32
1

Might be easier to query it :

 string PosTag = (string)JToken.Parse(jsonResponse).SelectToken("$..PosTag");
Slai
  • 22,144
  • 5
  • 45
  • 53