Home > Software engineering >  C#, converting a case statement to a yield statement
C#, converting a case statement to a yield statement

Time:11-23

I want to convert this statement to build a list of VM images to use in testing into something more elegant using the yield keyword, but the syntax is elluding me.

Desired end goal.

List<VmImages> images;
images[0] - WindowsServer2019
images[1] - WindowsServer2016
images[2] - RhelServer;
images[3] - OpenLogic;

Today the code looks like this:

            for (var i = 0; i < LinuxVMs; i  )
            {
                switch (i)
                {
                    case 0:
                        linuxDistros.Add(ConfigLoader.redHat);
                        break;
                    case 1:
                        linuxDistros.Add(ConfigLoader.openLogic);
                        break;
                    case 2:
                        linuxDistros.Add(ConfigLoader.suse);
                        break;
                    case 3:
                        linuxDistros.Add(ConfigLoader.ubuntu);
                        break;

                }

            }

This feels like a good case to use the yield keyword to simplify the logic into something like this, where I call GetLinuxVMs() for x number of times, where X is the count of LinuxVMs.

        private static IEnumerable<VmDistribution> GetLinuxVmDistros()
        {
            yield return ConfigLoader.redHat;
            yield return ConfigLoader.openLogic;
            yield return ConfigLoader.suse;
            yield return ConfigLoader.canonical;
        }

I'm not sure how to integrate this into my code, this is what I've tried:

            for (var i = 0; i < LinuxVMs; i  )
            {
                linuxDistros.Add(GetLinuxVmDistros());
            }

Since I get an IEnum back from the GetLinuxVmDistros method every time, I am puzzled as to how this is supposed to work at all.

CodePudding user response:

From your stated "desired end goal"

List<VmImages> images = new(){
    WindowsServer2019,
    WindowsServer2016,
    RhelServer,
    OpenLogic,
}

All the rest of the looping/finagling is just confusing the issue, IMHO

CodePudding user response:

GetLinuxVmDistros() will return an IEnumerable<VmDistribution> as per your definition.

It seems you want to add to a collection called linuxDistros another collection.

If linuxDistros is a List<VmDistribution>, simply use the AddRange method:

linuxDistros.AddRange(GetLinuxVmDistros());

See: https://docs.microsoft.com/fr-fr/dotnet/api/system.collections.generic.list-1.addrange?view=net-6.0

But I fail to see the point of creating an Enumerable just for this.

CodePudding user response:

I'm not certain what you try to achieve since the naming is .. not clear. But with this code below, it works:

class ConfigLoader
{
    static public VmDistribution redHat { get; set; } = VmDistribution.a;
    static public VmDistribution openLogic { get; set; } = VmDistribution.b;
    static public VmDistribution suse { get; set; } = VmDistribution.c;
    static public VmDistribution canonical { get; set; } = VmDistribution.d;
}

enum VmDistribution { a, b, c, d }
IEnumerable<VmDistribution> GetLinuxVmDistros()
{
    yield return ConfigLoader.redHat;
    yield return ConfigLoader.openLogic;
    yield return ConfigLoader.suse;
    yield return ConfigLoader.canonical;
}

var list = new List<VmDistribution>();
list.AddRange(GetLinuxVmDistros());

Notice that in the end I'm invoking GetLinuxVmDistros() only once, and the list is filled with method list.AddRange().

CodePudding user response:

In your example you should do whatever you need to do with the items with the loop.

for (var i = 0; i < LinuxVMs; i  )
{
    ProcessItem(LinuxVMs[i]);
}

Having said that, there's isn't much point in yielding on such a small set of results. The main purpose of yield return is to allow a large collection to be returned 1 item at a time, where the calling code may want to stop iterating over the items at any point. Another usage is where fetching all items at once may be very expensive resource-wise.

For example, you may not want to continue if 1 item couldn't be processed for whatever reason.

for (var i = 0; i < LinuxVMs; i  )
{
    var result = ProcessItem(LinuxVMs[i]);
    
    if (!result.Success)
    {
        break;
    }
}
  • Related