如何使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<> 。
答案 0 :(得分:90)
您需要将非通用IEnumerable
“解除”为IEnumerable<string>
。有人建议您使用OfType
,但这是一种过滤方法。你正在做的是相当于一个演员,其中有Cast
运算符:
var fields = RequestFields().Cast<string>();
正如Frans所指出的,这只能提供对密钥的访问。您仍然需要为值集合索引。以下是从KeyValuePair
:
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);
}
答案 1 :(得分:11)
AsQueryable
必须使用IEnumerable<T>
,一般。 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"));
}
答案 2 :(得分: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);
}
}
答案 3 :(得分:6)
我知道我迟到了,但只是想添加我的答案,不涉及.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]));
}
希望这可以帮助任何未来的访客
答案 4 :(得分:4)
问题是集合实现IEnumerable
(而不是IEnumerable<T>
)并枚举集合返回键,而不是对。
如果我是你,我会使用一个可枚举的Dictionary<string, string>
,可以与LINQ一起使用。
答案 5 :(得分:3)
对我来说,@ Bryan Watts'(+ 1'd)答案的ToLookup
变体代表了迄今为止最简单的以只读方式使用它的方法。
对于我的用例,我正在操作一个查询字符串以便与Linq2Rest一起使用,并且还需要将其全部重新转换为NameValueCollection
,所以我有一组扩展方法for 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;
}
}
答案 6 :(得分: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)