How to make NameValueCollection
accessible to LINQ query operator such as where, join, groupby?
I tried the below:
private NameValueCollection RequestFields()
{
NameValueCollection nvc = new NameValueCollection()
{
{"emailOption: blah Blah", "true"},
{"emailOption: blah Blah2", "false"},
{"nothing", "false"},
{"nothinger", "true"}
};
return nvc;
}
public void GetSelectedEmail()
{
NameValueCollection nvc = RequestFields();
IQueryable queryable = nvc.AsQueryable();
}
But I got an ArgumentException telling me that the source is not IEnumerable<>.
You need to "lift" the non-generic IEnumerable
to an IEnumerable<string>
. It has been suggested that you use OfType
but that is a filtering method. What you're doing is the equivalent of a cast, for which there is the Cast
operator:
var fields = RequestFields().Cast<string>();
As Frans pointed out, this only provides access to the keys. You would still need to index into the collection for the values. Here is an extension method to extract KeyValuePair
s from the NameValueCollection
:
public static IEnumerable<KeyValuePair<string, string>> ToPairs(this NameValueCollection collection)
{
if(collection == null)
{
throw new ArgumentNullException("collection");
}
return collection.Cast<string>().Select(key => new KeyValuePair<string, string>(key, collection[key]));
}
Edit: In response to @Ruben Bartelink's request, here is how to access the full set of values for each key using ToLookup
:
public static ILookup<string, string> ToLookup(this NameValueCollection collection)
{
if(collection == null)
{
throw new ArgumentNullException("collection");
}
var pairs =
from key in collection.Cast<String>()
from value in collection.GetValues(key)
select new { key, value };
return pairs.ToLookup(pair => pair.key, pair => pair.value);
}
Alternatively, using C# 7.0 tuples:
public static IEnumerable<(String name, String value)> ToTuples(this NameValueCollection collection)
{
if(collection == null)
{
throw new ArgumentNullException("collection");
}
return
from key in collection.Cast<string>()
from value in collection.GetValues(key)
select (key, value);
}
AsQueryable
must take an IEnumerable<T>
, a generic. NameValueCollection
implements IEnumerable
, which is different.
Instead of this:
{
NameValueCollection nvc = RequestFields();
IQueryable queryable = nvc.AsQueryable();
}
Try OfType (it accepts the non-generic interface)
{
NameValueCollection nvc = RequestFields();
IEnumerable<string> canBeQueried = nvc.OfType<string>();
IEnumerable<string> query =
canBeQueried.Where(s => s.StartsWith("abc"));
}
I know I'm late to the party but just wanted to add my answer that doesn't involve the .Cast
extension method but instead uses the AllKeys property:
var fields = RequestFields().AllKeys;
This would allow the following extension method:
public static IEnumerable<KeyValuePair<string, string>> ToPairs(this NameValueCollection collection)
{
if(collection == null)
{
throw new ArgumentNullException("collection");
}
return collection.AllKeys.Select(key => new KeyValuePair<string, string>(key, collection[key]));
}
Hope this helps any future visitors
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With