The OrangeGoblin
The OrangeGoblin

Reputation: 794

Select from Enum using Linq

I have two properties in an object, ChannelName and ChannelValue. I have an Enum with a list of channel Id's.

I want to be able to use a Linq query to say, "select the channel value where the channel name = one of the items in the Enum."

I have this so far, but I get the error:

Cannot implicitly convert type 'System.Collections.Generic.IEnumerable' to 'string'

The code is:

 var channels = Enum.GetNames(typeof(ModbusChannels)).ToList();
            var allChannelValues = "";

            foreach (var item in channels)
            {
                allChannelValues = (from x in data where x.ChannelName.Contains(item) select x.ChannelValue);
            }

FYI, where 'data' appears in the appears in the query, this is an object that is fully populated.

The Enum has 500 names in it, but here is a shortened version:

 public enum ModbusChannels{
        M0,
        M1,
        M2,
        M3,
        M4,
        M5,
        M6,
        M7,
        M8
}

Is this the right way to do this and how do I achieve the query.

Upvotes: 0

Views: 12197

Answers (3)

Lance U. Matthews
Lance U. Matthews

Reputation: 16606

The reason for that error is because allChannelValues is of type string, whereas the from x in data ... expression you are attempting to assign to allChannelValues results in an IEnumerable<ChannelValueType>, where ChannelValueType is the same type as x.ChannelValue. As the error states, an IEnumerable<ChannelValueType> cannot be implicitly converted to string to store in allChannelValues.

The other answers provide a more efficient way to do this, but just to "finish the thought" of what you had started to do...

List<string> channels = Enum.GetNames(typeof(ModbusChannels)).ToList();
IEnumerable<ChannelValueType> allChannelValues = Enumerable.Empty<ChannelValueType>();

foreach (string item in channels)
{
    IEnumerable<ChannelValueType> channelValues = from x in data
                                                  where x.ChannelName.Contains(item)
                                                  select x.ChannelValue;

    allChannelValues = allChannelValues.Concat(channelValues);
}

string allChannelValuesText = string.Join(", ", allChannelValues);

Declaring allChannelValues with the appropriate type is all that is needed to eliminate the error.

You were also assigning allChannelValues on every iteration of the foreach, so at the completion of the loop allChannelValues would contain the result of only the last iteration. Instead, we store the query results in channelValues and then concatenate that to allChannelValues to save the cumulative results of the loop; allChannelValues is initialized with an empty enumerable so there is something on which to call .Concat() on the first iteration.

Finally, we use string.Join() to build a comma-separated string of the resulting ChannelValue values. It is not until this line is executed that the LINQ queries/methods in the foreach block are actually evaluated, but that does not affect the result.

Upvotes: 1

Igor
Igor

Reputation: 62213

The way I am reading your question is that you want to see if the string value of the property ChannelName exists as a name in the enumeration ModbusChannels.

List<string> channels = Enum.GetNames(typeof(ModbusChannels)).ToList();
var allChannelValues = data
                   .Where(x => channels.Contains(x.ChannelName))
                   .Select(x => x.ChannelValue)
                   .ToList();

This will not work if this string value contains multiple values like a CSV string. In that case it would be more clear if you included sample values.

Upvotes: 1

Selman Gen&#231;
Selman Gen&#231;

Reputation: 101681

You can use Contains to check if enum values contain the channel name:

var channels = Enum.GetNames(typeof(ModbusChannels)).ToList();
var allChannelValues = data.Where(d => channels.Contains(d.ChannelName)).ToList();

Upvotes: 5

Related Questions