1

I have the following code:

var maxCodes = Math.Max(pCodes.Count, poCodes.Count);
for (var i = maxCodes - 1; i > -1; i--)
{
    var code = (i < pCodes.Count) ? pCodes.ElementAt(i) : new pCodeDto();
    //....
}

My issue is I am getting an ArgumentOutOfRangeException and I am wondering if it could be being caused by the line of code with the ternary expression? This is an emailed exception from a client, so for now it is all I have.

I am wondering if the whole of this expression:

var code = (i < pCodes.Count) ? pCodes.ElementAt(i) : new pCodeDto();

gets evaluated before the code decides which route to go down, which could be a cause of this exception? This is single threaded code.

pCodes and poCodes are both ICollections

Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
Alex
  • 3,730
  • 9
  • 43
  • 94
  • You can use a debugger to step through the logic – Bernard Vander Beken Jan 05 '18 at 12:17
  • 2
    Yes if `i < 0`. What is the type of `pCodes`? – Lee Jan 05 '18 at 12:17
  • 3
    Is this code that is run in a multi-threaded environment where elements can be removed from the collection? If so, you may need to add some locking around the collection. Can you add more information, a larger code snippet, what the collection is, multi-threading, etc. – pstrjds Jan 05 '18 at 12:19
  • 2
    You mention `pCodes` is an array, but those throw `IndexOutOfRangeException` and don't have a `Count` property - I assume it's a `List`? – C.Evenhuis Jan 05 '18 at 12:20
  • 3
    Any answer beyond clarifying that the ternary operator's operands are lazily evaluated will be pure guesswork at this stage… – dumetrulo Jan 05 '18 at 12:22
  • 2
    @pstrjds That wouldn't enter the `for` loop as it doesn't meet the condition of `i > -1` – Camilo Terevinto Jan 05 '18 at 12:24
  • @CamiloTerevinto - I just saw that - I had jumped on the maxCodes - 1 line and brain just filled in the expected remaining details. – pstrjds Jan 05 '18 at 12:24
  • Just wondering, what's the point of the `Max` there, if you don't use `poCodes`? – Camilo Terevinto Jan 05 '18 at 12:39
  • 3
    My recommendation is to rewrite this question and split it into two questions - the first question (which has an accepted answer) is "What is the order of evaluation for the conditional/ternary operator and its conditions" and the second question would be "Why is this code throwing an ArgumentOutOfRange exception when there are conditionals to help prevent that case" and in that question you should explain what the underlying `ICollection` is for your `pCodes` and `poCodes` and ensure that you don't have a typo where you are checking the size of `pCodes` but using `poCodes`. – pstrjds Jan 05 '18 at 12:44
  • @pstrjds: I agree, its a mess. And the only way this exact code is failing in a single threaded environment is if `pCodes.Count` is returning an incorrect value... which we cannot confirm from just this code. The new question needs to provide enough code to replicate the issue. Also, the OP has admitted they are not even sure if this code if causing the problem anyway! – musefan Jan 05 '18 at 12:48
  • I was just wondering if this ICollection is a custom made class :-) I guess you were faster than me @pstrjds – Zorkind Jan 05 '18 at 12:49
  • @Alex - I was saying that it was not clear, in that you really were asking two separate questions, one of which is very easily answered by simply reading the documentation for the conditional/ternary operator or by just throwing together a trivial example in LinqPad or something like that. Your second question is why are you getting the exception. The question is a bit of a mess because most people seem to have come to the conclusion that your question is "why the exception" (see close reason), but your actual question is about the `?` operator (which you have verified by answer selection). – pstrjds Jan 05 '18 at 14:08
  • @pstrjds thank you for the comment. I note your comments, but do contend that it is quite clear what I am asking if the question is read - I explicitly state the question more than once. In future will not add extra information as I have done in this question. I feel I got a lot of comments on this question, but if those commenting had read the question, maybe they would feel I am not as bad as they say I am. – Alex Jan 05 '18 at 14:12
  • @Alex - Take it not personally, no one is saying you are bad. I also fell into the trap of trying to psychic debug the question and asking for details to try to answer the "underlying" question, which is the exception. I believe we all fell into trying to answer the "underlying" question due to the well documented behavior of the `?` operator and the ease with which that could have been ruled out as a culprit. Writing good questions is hard. – pstrjds Jan 05 '18 at 14:19
  • @Alex: If you want to ask how the ternary operator works then you should just ask that. Don't confuse it with irrelevant code and exceptions. But then, you don't need to ask because somebody else [already asked for you](https://stackoverflow.com/questions/463155/how-does-the-ternary-operator-work) – musefan Jan 05 '18 at 15:04
  • @musefan sometimes people complain if you do not give enough information, and sometimes if you give too much information. Asking questions on SO is an art it seems rather than a science – Alex Jan 05 '18 at 15:21

2 Answers2

11

Only one of the two operands is evaluated, depending on the outcome of the condition.

It can still fail for quite some reasons.

One is that i is lower than 0, which will let the first evaluation result to true. Then the ElementAt will fail. Another reason might be a multi-threaded application that changes pCodes between the two evaluations.

Patrick Hofman
  • 153,850
  • 22
  • 249
  • 325
  • Just wondering, how can `i` be lower than zero with the condition `i > -1`? I honestly don't see how that code can fail with `ArgumentOutOfRangeException`. I think the excepting is thrown in some other code that is not in the question. Also the OP clearly mentioned that the app is single threaded. I would remove the guesswork part from the answer. – Racil Hilan Jan 05 '18 at 13:32
  • It can't be. The original post didn't say anything about threading, and the original post has this C#: `var code = (i < pCodes.Count) ? pCodes.ElementAt(i) : new pCodeDto();`. The current question deviates from the one that was answered. @RacilHilan – Patrick Hofman Jan 05 '18 at 13:35
7

Given

condition ? expression-if-true : expression-if-false

the condition is evaluated, then one of the two expressions (not both), as per the C# language reference.

https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/conditional-operator

Bernard Vander Beken
  • 4,848
  • 5
  • 54
  • 76