3 回答

TA貢獻1874條經驗 獲得超12個贊
.ToDictionary
要求每一個key
都是獨一無二的,通過設計。Linq 沒有
.DistinctBy( x => x.y )
方法,但我們可以使用.GroupBy( x => x.y ).Select( grp => grp.Last() )
. 這具有丟棄具有相同值的所有先前結果的效果y
。
因此,如果您首先按 HTTP 標頭名稱分組,然后選擇每個組中的最后一項,那么這將得到您想要的:
// Using cached static fields to avoid unnecessary array allocation:
static readonly String[] _splitOnLines = new String[] { "\r\n" };
static readonly String[] _splitHeader = new String[] { ": " };
public static Dictionary<String,String> CreateLookupDictionary(String input)
{
Debug.WriteLine(input);
return input
.Split( _splitOnLines , StringSplitOptions.RemoveEmptyEntries )
.Select( line => line.Split( _splitHeader, StringSplitOptions.None ) )
.Where( arr => arr.Length == 2 ) // filter out invalid lines, if any
.Select( arr => ( name: arr[0], value: arr[1] ) ) // using C# 7 named tuples for maintainability
.GroupBy( header => header.name )
.Select( duplicateHeaderGroup => duplicateHeaderGroup.Last() )
.ToDictionary( header => header.name, header.value, StringComparer.InvariantCultureIgnoreCase );
}
或者,使用自定義聚合,該聚合使用始終成功的鍵索引Item設置器屬性。如果與我之前的示例相比很少有重復項,則此方法可能具有更快的性能。
public static Dictionary<String,String> CreateLookupDictionary(String input)
{
Debug.WriteLine(input);
return input
.Split( _splitOnLines , StringSplitOptions.RemoveEmptyEntries )
.Select( line => line.Split( _splitHeader, StringSplitOptions.None ) )
.Where( arr => arr.Length == 2 )
.Select( arr => ( name: arr[0], value: arr[1] ) )
.Aggregate(
new Dictionary<String,String>( StringComparer.InvariantCultureIgnoreCase ),
( d, header ) =>
{
d[ header.name ] = header.value;
return d;
}
);
}

TA貢獻1804條經驗 獲得超3個贊
.Net Core 2.0 有解決辦法:
使用 Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpParser 類:
如果您使用這種方法,您將能夠處理許多無法預料的邊緣情況。
這是偽代碼(未經測試)——這只適用于 .Net Core(顯然)
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
using System;
using System.Buffers;
using System.Collections.Generic;
using System.Text;
public class ExampleUsage?
{
? ? public static void Main(string[] args)
? ? {
? ? ? ? string requestString =
? ? ? ? @"POST /resource/?query_id=0 HTTP/1.1
? ? ? ? Host: example.com
? ? ? ? User-Agent: custom
? ? ? ? Accept: */*
? ? ? ? Connection: close
? ? ? ? Content-Length: 20
? ? ? ? Content-Type: application/json
? ? ? ? {""key1"":1, ""key2"":2}";
? ? ? ? var headerResult = Parser.Parse(requestString);
? ? }
}
public class Parser : IHttpHeadersHandler
{
? ? private Dictionary<string, string> result = null;
? ? public Dictionary<string, string> Parse(string requestString)
? ? {
? ? ? ? result = new Dictionary<string, string>();??
? ? ? ? byte[] requestRaw = Encoding.UTF8.GetBytes(requestString);
? ? ? ? ReadOnlySequence<byte> buffer = new ReadOnlySequence<byte>(requestRaw);
? ? ? ? HttpParser<Program> parser = new HttpParser<Program>();
? ? ? ? parser.ParseRequestLine(this, buffer, out var consumed, out var examined);
? ? ? ? buffer = buffer.Slice(consumed);
? ? ? ? parser.ParseHeaders(this, buffer, out consumed, out examined, out var b);
? ? ? ? buffer = buffer.Slice(consumed);
? ? }
? ? public void OnHeader(Span<byte> name, Span<byte> value)
? ? {
? ? ? ? result.Add(Encoding.UTF8.GetString(name), Encoding.UTF8.GetString(value));
? ? }
}

TA貢獻1818條經驗 獲得超11個贊
就我個人而言,我會使用它.ToLookup來保留同一個鍵的多個值。 .ToLookup不會在重復鍵上出錯,它會創建一個IEnumerable<V>值,這種情況是IEnumerable<string>:
public static ILookup<string, string> CreateLookup(string input)
{
Debug.WriteLine(input);
return input.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries)
.Select(x => x.Split(new string[] {": "}, StringSplitOptions.None))
.ToLookup(x => x[0], x => x[1], StringComparer.InvariantCultureIgnoreCase);
}
- 3 回答
- 0 關注
- 200 瀏覽
添加回答
舉報