.net 使 LINQ 查询可以访问 NameValueCollection

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/391023/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 10:52:51  来源:igfitidea点击:

Make NameValueCollection accessible to LINQ Query

.netlinqnamevaluecollection

提问by Graviton

How to make NameValueCollectionaccessible to LINQ query operator such as where, join, groupby?

如何使NameValueCollectionLINQ 查询运算符(例如 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 ArgumentExceptiontelling me that the source is not IEnumerable<>.

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

回答by Bryan Watts

You need to "lift" the non-generic IEnumerableto an IEnumerable<string>. It has been suggested that you use OfTypebut that is a filtering method. What you're doing is the equivalent of a cast, for which there is the Castoperator:

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

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 KeyValuePairs from the NameValueCollection:

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

Edit:In response to @Ruben Bartelink's request, here is how to access the full set of values for each key using ToLookup:

编辑:为了响应@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);
}

Alternatively, using C# 7.0 tuples:

或者,使用 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);
}

回答by Amy B

AsQueryablemust take an IEnumerable<T>, a generic. NameValueCollectionimplements IEnumerable, which is different.

AsQueryable必须采用IEnumerable<T>,泛型。NameValueCollection实现IEnumerable,这是不同的。

Instead of this:

取而代之的是:

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

Try OfType(it accepts the non-generic interface)

Try OfType(它接受非通用接口)

{
    NameValueCollection nvc = RequestFields();
    IEnumerable<string> canBeQueried = nvc.OfType<string>();
    IEnumerable<string> query =
       canBeQueried.Where(s => s.StartsWith("abc"));
}

回答by NinjaNye

I know I'm late to the party but just wanted to add my answer that doesn't involve the .Castextension method but instead uses the AllKeys property:

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

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

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

回答by Orion Adrian

A dictionary is probably actually closer to what you want to use since it will actually fill more of the roles that NameValueCollection fills. This is a variation of Bryan Watts' solution:

字典实际上可能更接近您想要使用的内容,因为它实际上会填充 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); 
    }
}

回答by Frans Bouma

The problem is that the collection implements IEnumerable(as opposed to IEnumerable<T>) and enumerating the collection returns the keys, not the pairs.

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

If I were you, I'd use a Dictionary<string, string>which is enumerable and can be used with LINQ.

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

回答by Ruben Bartelink

For me, @Bryan Watts' (+1'd) answer's ToLookupvariant represents by far the clearest approach for using it on a read-only basis.

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

For my use case, I'm manipulating a query string for use with Linq2Restand also need to turn it all back into a NameValueCollectionat the end, so I have a set of extension methods for NameValueCollectionwhich offer more granular operations (to operate both per parameter name (AsEnumerable) and per argument (AsKeyValuePairs)) and also the inverse operation of converting it back ToNameValueCollection(from either representation)).

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

Example consumption:

消费举例:

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

Code:

代码:

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

回答by Derek Ziemba

I don't really see why anyone would need to add an extension method.
Here's some different ways to do it in VB.NET. It includes 4 different intermediate forms of IEnumerable: Array, Tuple, Anonymous, and KeyValuePair. For the C# equivalent go to converter.telerik dot com and convert it.

我真的不明白为什么有人需要添加扩展方法。
这是在 VB.NET 中执行此操作的一些不同方法。它包括 IEnumerable 的 4 种不同的中间形式: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)