65

如何使NameValueCollectionLINQ 查询运算符(例如 where、join、groupby)可以访问?

我尝试了以下方法:

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();
}

但是我得到一个ArgumentException告诉我源不是 IEnumerable<>

4

7 回答 7

96

您需要将非泛型“提升”IEnumerableIEnumerable<string>. 有人建议您使用OfType,但这是一种过滤方法。你正在做的是相当于一个演员,其中有Cast运营商:

var fields = RequestFields().Cast<string>();

正如 Frans 指出的那样,这仅提供对密钥的访问。您仍然需要对值的集合进行索引。KeyValuePair这是从 中提取s的扩展方法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]));
}

编辑:响应@Ruben Bartelink 的请求,这里是如何使用以下方法访问每个键的完整值集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);
}

或者,使用 C# 7.0 元组:

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);
}
于 2008-12-28T18:38:03.803 回答
11

AsQueryable必须取一个IEnumerable<T>,一个泛型。NameValueCollection实现IEnumerable,这是不同的。

而不是这个:

{
    NameValueCollection nvc = RequestFields();
    IQueryable queryable = nvc.AsQueryable();
}

Try OfType(它接受非泛型接口)

{
    NameValueCollection nvc = RequestFields();
    IEnumerable<string> canBeQueried = nvc.OfType<string>();
    IEnumerable<string> query =
       canBeQueried.Where(s => s.StartsWith("abc"));
}
于 2008-12-24T15:15:22.873 回答
10

我知道我迟到了,但只是想添加不涉及.Cast扩展方法而是使用 AllKeys 属性的答案:

var fields = RequestFields().AllKeys;

这将允许以下扩展方法:

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]));
}

希望这可以帮助任何未来的访客

于 2013-09-17T15:59:43.420 回答
8

字典实际上可能更接近您想要使用的内容,因为它实际上会填充 NameValueCollection 填充的更多角色。这是 Bryan Watts 解决方案的变体:

public static class CollectionExtensions
{
    public static IDictionary<string, string> ToDictionary(this NameValueCollection source)
    {
        return source.Cast<string>().Select(s => new { Key = s, Value = source[s] }).ToDictionary(p => p.Key, p => p.Value); 
    }
}
于 2010-06-07T15:21:26.680 回答
4

问题是集合实现IEnumerable(而不是IEnumerable<T>)并枚举集合返回键,而不是对。

如果我是你,我会使用一个Dictionary<string, string>可枚举的并且可以与 LINQ 一起使用的。

于 2008-12-24T08:36:52.320 回答
3

对我来说,@Bryan Watts(+1'd)答案的ToLookup变体代表了迄今为止在只读基础上使用它的最清晰的方法。

对于我的用例,我正在处理一个与Linq2Rest一起使用的查询字符串,并且还需要在NameValueCollection最后将其全部转换为 a,因此我有一组扩展方法,NameValueCollection它们提供了更精细的操作(每个参数都可以操作)名称 ( AsEnumerable) 和每个参数 ( AsKeyValuePairs)) 以及将其转换回来的逆操作ToNameValueCollection(从任一表示形式))。

消费示例:

public static NameValueCollection WithoutPagingOperators( this NameValueCollection that )
{
    return that.AsEnumerable()
        .Where( @param => @param.Key != OdataParameters.Skip 
          && @param.Key != OdataParameters.Top )
        .ToNameValueCollection();
}

代码:

using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;

public static class NamedValueCollectionExtensions
{
    public static IEnumerable<KeyValuePair<string, string[]>> AsEnumerable( this NameValueCollection that )
    {
        return that
            .Cast<string>() // doesn't implement IEnumerable<T>, but does implement IEnumerable
            .Select( ( item, index ) => // enable indexing by integer rather than string
                new KeyValuePair<string, string[]>( item, that.GetValues( index ) ) ); // if you use the indexer or GetValue it flattens multiple values for a key, Joining them with a ',' which we don't want
    }

    public static IEnumerable<KeyValuePair<string, string>> AsKeyValuePairs( this IEnumerable<KeyValuePair<string, string[]>> that )
    {
        return that
            .SelectMany( item =>
                item.Value.Select( value =>
                    new KeyValuePair<string, string>( item.Key, value ) ) );
    }

    public static NameValueCollection ToNameValueCollection( this IEnumerable<KeyValuePair<string, string[]>> that )
    {
        return that.AsKeyValuePairs().ToNameValueCollection();
    }

    public static NameValueCollection ToNameValueCollection( this IEnumerable<KeyValuePair<string, string>> that )
    {
        var result = new NameValueCollection();
        foreach ( KeyValuePair<string, string> item in that )
            result.Add( item.Key, item.Value );
        return result;
    }
}
于 2012-10-03T13:01:53.283 回答
1

我真的不明白为什么有人需要添加扩展方法。
以下是在 VB.NET 中执行此操作的一些不同方法。它包括 4 种不同的 IEnumerable 中间形式:Array、Tuple、Anonymous 和 KeyValuePair。对于 C# 等效项,请访问 converter.telerik dot com 并对其进行转换。

Dim nvc As New NameValueCollection() From {{"E", "55"}, {"A", "11"}, {"D", "44"}, {"C", "33"}, {"G", "66"}, {"B", "22"}}

Dim dictStrings As Dictionary(Of String, String) = nvc.Cast(Of String).ToDictionary(Function(key) key, Function(key) nvc(key))
Dim Ints2Chars__ As Dictionary(Of Integer, Char) = nvc.Cast(Of Object).ToDictionary(Function(key) CInt(nvc(CStr(key))), Function(key) CChar(key))

Dim arrEnumerable__ = From x In nvc.Cast(Of String) Select {x, nvc(x)}
Dim tupleEnumerable = From x In nvc.Cast(Of String) Select Tuple.Create(x, nvc(x))
Dim anonEnumerable_ = From X In nvc.Cast(Of String) Select New With {X, .Y = nvc(X)}
Dim kvpEnumerable__ = From x In nvc.Cast(Of String) Select New KeyValuePair(Of String, String)(x, nvc(x))

Dim anonQuery = From anon In anonEnumerable_ Let n = CInt(anon.Y) Order By n Where n > 30 Select New With {.num = n, .val = anon.X}
Dim dictQuery = anonQuery.ToDictionary(Of Integer, String)(Function(o) o.num, Function(o) o.val)


Dim dictArray_ = arrEnumerable__.ToDictionary(Function(x) x(0), Function(x) x(1))
Dim dictTuples = tupleEnumerable.ToDictionary(Function(tuple) tuple.Item1, Function(tuple) tuple.Item2)
Dim dictAnon__ = anonEnumerable_.ToDictionary(Function(anon) anon.X, Function(anon) anon.Y)
Dim dictKVPrs_ = kvpEnumerable__.ToDictionary(Function(kvp) kvp.Key, Function(kvp) kvp.Value)
于 2016-01-13T04:30:19.023 回答