使NameValueCollection可被LINQ Query访问
如何使NameValueCollection
访问LINQ查询运算符,如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 <> 。
您需要将非genericsIEnumerable
“提升”为IEnumerable<string>
。 有人build议你使用OfType
但这是一种过滤方法。 你正在做的是相当于一个演员,为此Cast
:
var fields = RequestFields().Cast<string>();
正如Frans指出的,这只能提供对密钥的访问。 你仍然需要索引值的集合。 以下是从NameValueCollection
提取KeyValuePair
的扩展方法:
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); }
AsQueryable
必须采用IEnumerable<T>
,一个generics。 NameValueCollection
实现IEnumerable
,这是不同的。
而不是这个:
{ NameValueCollection nvc = RequestFields(); IQueryable queryable = nvc.AsQueryable(); }
尝试OfType (它接受非通用接口)
{ NameValueCollection nvc = RequestFields(); IEnumerable<string> canBeQueried = nvc.OfType<string>(); IEnumerable<string> query = canBeQueried.Where(s => s.StartsWith("abc")); }
字典实际上可能更接近你想要使用的,因为它实际上会填充更多的NameValueCollection填充的angular色。 这是Bryan Watts解决scheme的变体:
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); } }
我知道我迟到了,但只是想添加我的答案,不涉及.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])); }
希望这有助于未来的访问者
问题是,集合实现IEnumerable
(而不是IEnumerable<T>
)枚举集合返回键,而不是对。
如果我是你,我会使用一个Dictionary<string, string>
这是可枚举的,可以用于LINQ。
对我来说,@Bryan Watts(+ 1'd)答案的ToLookup
变体是迄今为止在只读的基础上使用它的最清晰的方法。
对于我的用例,我操纵一个查询string与Linq2Rest一起使用,并且还需要将它全部变回到NameValueCollection
的末尾,所以我有一套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; } }
我不明白为什么有人需要添加扩展方法。
这里有一些不同的方式来在VB.NET中做到这一点。 它包括4种不同的IEnumerable中间forms:数组,元组,匿名和KeyValuePair。 对于C#等价于转换converter.telerik点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)