Sami-L
Sami-L

Reputation: 5705

C# - Ternary inside anonymous object

Below is a an anonymous object, assuming that Course object can have no related Progress object, so to avoid having Progress return an empty array, I am trying to make it return an object with values equal to zeroes:

var courses = await _context.courses
    .Include(c => c.Progress)
    .ToListAsync();

var myCourses = courses
    .Select(c => new
    {
        Title = c.Title,
        Progress = (c.Progress.ToList().Select(x => new { x.CurrentChapter, x.Completed }) != null)
            ? (c.Progress.ToList().Select(x => new { x.CurrentChapter, x.Completed }))
            : (new List<Dictionary<string, int>> { { "CurrentChapter", 0 }, { "Completed", 0 } })
    })
    .ToList();
    
return Ok(myCourses);

But I am getting an error in the last part of the ternary as follows:

No overload for method 'Add' takes 2 arguments

Upvotes: 0

Views: 453

Answers (2)

Sami-L
Sami-L

Reputation: 5705

Discussion with @Flydog57 helped me dissipate some confusion since this is the first time I make a ternary inside an anonymous object, and after made some edits to my question to make it short and concise, and some research, I could finally solve the issue, here is what I ended up to:

var myCourses = courses
    .Select(c => new
    {
        Title = c.Title,
        Progress = (c.Progress.Any())
                    ? (c.Progress.ToList().Select(x => new { x.CurrentChapter, x.Completed }))
                    : (new[] { new {CurrentChapter = 0, Completed = 0} }.ToList())
    })
    .ToList();

So using Dictionary in the last part was not the correct way, and also the first part was not relevant, so now instead of returning:

{
    "title": "Course having child Progress objects",
    "progress": [
        {
            "currentChapter": 2,
            "completed": 0
        },
        {
            "currentChapter": 0,
            "completed": 0
        }
    ]
},
{
    "title": "Course having NO child Progress objects",
    "progress": []
}

it is returning:

{
    "title": "Course having child Progress objects",
    "progress": [
        {
            "currentChapter": 2,
            "completed": 0
        },
        {
            "currentChapter": 0,
            "completed": 0
        }
    ]
},
{
    "title": "Course having NO child Progress objects",
    "progress": [
        {
            "currentChapter": 0,
            "completed": 0
        }
    ]
}

Upvotes: 0

Flydog57
Flydog57

Reputation: 7111

Your code as you show it is not very salvageable (nor is it anywhere near readable). I took your code, removed the superfluous ToList calls and added a bit more to get it to nearly compile:

As I mentioned in the comments, the ToList calls are superfluous - course.Progress must be enumerable, all ToList does is create a new list that copies the information in course.Progress

My added code:

var course = new {Progress = new List<Progress>() };

That allows the course.Progress.Select call to make a little sense. If course isn't an instance of a type that has a property named Progress that implements IEnumerable<Progress, well, I'm not sure how to start this.

Then, the beginning of your code, reformatted starts making sense (it trails off at the end).

Here's your code, without .ToList and reformatted:

var progress = (course.Progress
    .Select(x => new { x.CurrentChapter, x.Completed }) != null)
    ? (course.Progress.Select(x => new { x.CurrentChapter, x.Completed })) 
    : (new List<Dictionary<string, int>{ { "CurrentChapter", 0 }, { "Completed", 0 } });

As I mentioned in the comments, IEnumerable<T>.Select never returns null, so the initial null check is useless. I'm guessing that you are trying to check that the progress collection is empty.

Also note that when you use a ternary, both possible choices must be the same type. In one case, you have an anonymous type, in the other, you have a Dictionary. That's never going to compile.

Like the other commenters, I think you are better off using an if/else. However, since you seem to want to get get an anonymously typed thing called Progress. I don't have a clue how you declared that, so I worked around it with a tuple. I think this is kinda-sorta what you are trying to do:

(int currentChapter, int completed) progressTuple;
if(!course.Progress.Any())
{
    progressTuple = (0, 0);
}
else
{
    var firstProgress = course.Progress.First();
    progressTuple = (firstProgress.CurrentChapter, firstProgress.Completed);
}
var progress = new { CurrentChapter = progressTuple.currentChapter, Completed = progressTuple.completed };

Now, progress is an anonymous type like you seem to want. Note that I picked the first item out of your collection. I don't really know what you wanted to do there.

Since you have a type named Progress that has the properties you wanted, this would make more sense:

Progress progress;
if (!course.Progress.Any())
{
    progress = new Progress { CurrentChapter = 0, Completed = 0 };
}
else
{
    progress  = course.Progress.First();
}

Now that you have code that is simplified and that makes sense, you could try reintroducing a ternary operator if your tastes run towards the unreadable (I find complex ternaries at the edge of my code comprehension skills).

Upvotes: 1

Related Questions