2

After enabling Sonar in my project I get the following message

myEntities is null on at least one execution path.

public static IEnumerable<KeyValuePair<MyDto,long>> PrepareClientResponses(this IEnumerable<MyServiceCnt> myEntities)
{
    if (myEntities == null || !myEntities.Any())
    {
        yield return default;
    }         
    foreach (var myEntities in myEntities)
    {
        var client = myEntities.PrepareClientResponse();
        yield return new KeyValuePair<MyDto, long>(client, myEntities.MyId.Value);
    }
}

The message is on the "myEntities" on the foreach (var myEntities in myEntities) line.

Can someone suggest me on how to solve this message. I am checking null condition but it still gives this warning.

coder11 b
  • 99
  • 5
  • `foreach (var myEntities in myEntities)` is wrong, you're using the very same variable! Shouldn't it be `foreach (var myEntity in myEntities)`? – Marco Mar 14 '23 at 07:44
  • @Marco `foreach (var myEntities in myEntities)` even *does not compile* since `myEntities` is also a parameter in the method. – Mustafa Özçetin Mar 15 '23 at 05:45
  • Its actually a copy paste mistake from myend..rectified in my code @Mustafa – coder11 b Mar 15 '23 at 10:23

2 Answers2

3

yield return default;

yield return roughly means "give back a value and continue once the next value is requested".

So, the loop is executed even if the yield return is never reached.

For fixing this, you have multiple options.

yield break

Instead of the yield return in the if, you can use yield break in order to terminate the method as explained here.

public static IEnumerable<KeyValuePair<MyDto,long>> PrepareClientResponses(this IEnumerable<MyServiceCnt> myEntities)
{
    if (myEntities == null || !myEntities.Any())
    {
        yield return default;
        yield break;
    }
    foreach (var e in myEntities)
    {
        var client = e.PrepareClientResponse();
        yield return new KeyValuePair<MyDto, long>(client, e.MyId.Value);
    }
    
} 

else

You can just put the loop in an else-block. This way, it won't be executed in case the check evaluates to true:

public static IEnumerable<KeyValuePair<MyDto,long>> PrepareClientResponses(this IEnumerable<MyServiceCnt> myEntities)
{
    if (myEntities == null || !myEntities.Any())
    {
        yield return default;
    }
    else
    {
        foreach (var e in myEntities)
        {
            var client = e.PrepareClientResponse();
            yield return new KeyValuePair<MyDto, long>(client, e.MyId.Value);
        }
    }
} 

do nothing

In some cases, it might be a sensible decision to not return any element in case a preconception fails. But note that your code will behave differently if you arr doing that.

public static IEnumerable<KeyValuePair<MyDto,long>> PrepareClientResponses(this IEnumerable<MyServiceCnt> myEntities)
{
    if (myEntities != null && myEntities.Any())
    {
        foreach (var e in myEntities)
        {
            var client = e.PrepareClientResponse();
            yield return new KeyValuePair<MyDto, long>(client, e.MyId.Value);
        }
    }
} 

other problem

Please see this other answer by @Marco for another problem with your code (which I also integrated in this answer).

dan1st
  • 12,568
  • 8
  • 34
  • 67
  • Good answer, I miised one error :) – Marco Mar 14 '23 at 07:56
  • I would have also missed the problem you found. – dan1st Mar 14 '23 at 08:03
  • Thanks , i have implemented the second case ie with "else " implementation and bug got resolved. Also have incorporated @Macros s point also to work. – coder11 b Mar 14 '23 at 15:24
  • @dan1st here yield return default; yield break; yield break is only needed here? Should i have yield return as well as yield break – coder11 b Mar 15 '23 at 20:10
  • if you use `yiels return default` before `yield break`, you woukd get the value `default` when iterating over it. If you just use `yield break;`, it will be empty. – dan1st Mar 15 '23 at 21:28
2

You have an error in your foreach loop: foreach (var myEntities in myEntities)

It is wrong because you're using the very same variable for the loop!
It should be:

foreach (var myEntity in myEntities)
{
    var client = myEntity.PrepareClientResponse();
    yield return new KeyValuePair<MyDto, long>(client, myEntity.MyId.Value);
}
Marco
  • 56,740
  • 14
  • 129
  • 152