这段代码是一个用于处理URL查询参数的C#工具类,主要提供解析和构建URL的功能。
namespace System
{
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Text;
public static class UrlHelper
{
/// <summary>
/// 解析URL中的参数。<br />
/// 注意:在<see cref="Dictionary{TKey, TValue}"/>中,直接读取不存在的键值对时,会抛出异常。<br />
/// <br />
/// 支持解析示例:<br />
/// https://www.google.com/index?page=1&lang=eng <br />
/// https://www.google.com/ <br />
/// https://www.google.com/index?page=title=index=1&lang=&chang&char=?&id=123 <br />
/// https://www.google.com/index? <br />
/// </summary>
/// <param name="url"></param>
/// <param name="baseUrlKey"> URL中符号“?”的前面部分,在返回的结果中,对应的关键字。</param>
/// <param name="ignoreCase"></param>
/// <returns></returns>
public static Dictionary<string, string> GetQueryDictionary(string url, string baseUrlKey = null, bool ignoreCase = false)
{
StringComparer comparer;
if (ignoreCase)
comparer = StringComparer.InvariantCultureIgnoreCase;
else
comparer = StringComparer.InvariantCulture;
return GetQueryDictionary(url, baseUrlKey, comparer);
}
/// <summary>
/// 解析URL中的参数。<br />
/// 注意:在<see cref="Dictionary{TKey, TValue}"/>中,直接读取不存在的键值对时,会抛出异常。<br />
/// <br />
/// 支持解析示例:<br />
/// https://www.google.com/index?page=1&lang=eng <br />
/// https://www.google.com/ <br />
/// https://www.google.com/index?page=title=index=1&lang=&chang&char=?&id=123 <br />
/// https://www.google.com/index? <br />
/// </summary>
/// <param name="url"></param>
/// <param name="baseUrlKey"> URL中符号“?”的前面部分,在返回的结果中,对应的关键字。</param>
/// <param name="comparer"></param>
/// <returns></returns>
public static Dictionary<string, string> GetQueryDictionary(string url, string baseUrlKey, StringComparer comparer)
{
// 第一个“?”符号的下标。
// 用于支持,参数中包括“?”符号的URL。
int indexQuestionMark = url.IndexOf('?');
int countQuery = url.Length - indexQuestionMark - 1;
Dictionary<string, string> info = null;
// 如果URL中包括有效的参数。
if (indexQuestionMark > -1 && countQuery > 0)
{
string queryString = url.Substring(indexQuestionMark + 1, countQuery);
// 为空的键值对没有意义,所以,舍弃为空的键值对。
string[] keyAndValuePairs = queryString.Split(new char[] { '&' }, StringSplitOptions.RemoveEmptyEntries);
info = new Dictionary<string, string>(keyAndValuePairs.Length + 1, comparer);
foreach (var pair in keyAndValuePairs)
{
// 第一个“=”符号的下标。
// 用于支持,value中包括“=”符号的参数。
int indexEquals = pair.IndexOf('=');
// 如果包含“=”符号。
if (indexEquals > -1)
{
string key = pair.Substring(0, indexEquals);
key = Uri.UnescapeDataString(key);
int countValue = pair.Length - indexEquals - 1;
// 避免“=”符号后面没有内容时,indexEquals + 1超出数组的有效索引。
string value = (countValue == 0) ? string.Empty : pair.Substring(indexEquals + 1, countValue);
value = Uri.UnescapeDataString(value);
info[key] = value;
}
// 用关键字保存特殊参数。
else
{
info[pair] = null;
}
}
}
info = info ?? new Dictionary<string, string>(comparer);
if (baseUrlKey != null)
{
if (indexQuestionMark < 0 || indexQuestionMark > url.Length)
{
indexQuestionMark = url.Length;
}
// URL中符号“?”的前面部分。
string baseUrlValue = url.Substring(0, indexQuestionMark);
info[baseUrlKey] = baseUrlValue;
}
return info;
}
/// <summary>
/// 解析URL中的参数。<br />
/// 注意:在<see cref="NameValueCollection"/>中,直接读取不存在的键值对时,返回null,不会抛出异常。<br />
/// <br />
/// 支持解析示例:<br />
/// https://www.google.com/index?page=1&lang=eng <br />
/// https://www.google.com/ <br />
/// https://www.google.com/index?page=title=index=1&lang=&chang&char=?&id=123 <br />
/// https://www.google.com/index? <br />
/// </summary>
/// <param name="url"></param>
/// <param name="baseUrlKey"> URL中符号“?”的前面部分,在返回的结果中,对应的关键字。</param>
/// <param name="ignoreCase"></param>
/// <returns></returns>
public static NameValueCollection GetQueryCollection(string url, string baseUrlKey = null, bool ignoreCase = false)
{
StringComparer comparer;
if (ignoreCase)
comparer = StringComparer.InvariantCultureIgnoreCase;
else
comparer = StringComparer.InvariantCulture;
return GetQueryCollection(url, baseUrlKey, comparer);
}
/// <summary>
/// 解析URL中的参数。<br />
/// 注意:在<see cref="NameValueCollection"/>中,直接读取不存在的键值对时,返回null,不会抛出异常。<br />
/// <br />
/// 支持解析示例:<br />
/// https://www.google.com/index?page=1&lang=eng <br />
/// https://www.google.com/ <br />
/// https://www.google.com/index?page=title=index=1&lang=&chang&char=?&id=123 <br />
/// https://www.google.com/index? <br />
/// </summary>
/// <param name="url"></param>
/// <param name="baseUrlKey"> URL中符号“?”的前面部分,在返回的结果中,对应的关键字。</param>
/// <param name="comparer"></param>
/// <returns></returns>
public static NameValueCollection GetQueryCollection(string url, string baseUrlKey, StringComparer comparer)
{
// 第一个“?”符号的下标。
// 用于支持,参数中包括“?”符号的URL。
int indexQuestionMark = url.IndexOf('?');
int countQuery = url.Length - indexQuestionMark - 1;
NameValueCollection info = null;
// 如果URL中包括有效的参数。
if (indexQuestionMark > -1 && countQuery > 0)
{
string queryString = url.Substring(indexQuestionMark + 1, countQuery);
// 为空的键值对没有意义,所以,舍弃为空的键值对。
string[] keyAndValuePairs = queryString.Split(new char[] { '&' }, StringSplitOptions.RemoveEmptyEntries);
info = new NameValueCollection(keyAndValuePairs.Length + 1, comparer);
foreach (var pair in keyAndValuePairs)
{
// 第一个“=”符号的下标。
// 用于支持,value中包括“=”符号的参数。
int indexEquals = pair.IndexOf('=');
// 如果包含“=”符号。
if (indexEquals > -1)
{
string key = pair.Substring(0, indexEquals);
key = Uri.UnescapeDataString(key);
int countValue = pair.Length - indexEquals - 1;
// 避免“=”符号后面没有内容时,indexEquals + 1超出数组的有效索引。
string value = (countValue == 0) ? string.Empty : pair.Substring(indexEquals + 1, countValue);
value = Uri.UnescapeDataString(value);
info.Add(key, value);
}
// 用关键字保存特殊参数。
else
{
info.Add(pair, null);
}
}
}
info = info ?? new NameValueCollection(comparer);
if (baseUrlKey != null)
{
if (indexQuestionMark < 0 || indexQuestionMark > url.Length)
{
indexQuestionMark = url.Length;
}
// URL中符号“?”的前面部分。
string baseUrlValue = url.Substring(0, indexQuestionMark);
info.Add(baseUrlKey, baseUrlValue);
}
return info;
}
public static string GetUrlQueryString(ICollection<KeyValuePair<string, string>> parameters)
{
List<string> pairs = new List<string>(parameters.Count);
foreach (KeyValuePair<string, string> item in parameters)
{
if (!string.IsNullOrEmpty(item.Value))
{
pairs.Add(string.Format("{0}={1}", Uri.EscapeDataString(item.Key), Uri.EscapeDataString(item.Value)));
}
}
return string.Join("&", pairs.ToArray());
}
public static string GetUrlQueryString(NameValueCollection parameters)
{
List<string> pairs = new List<string>(parameters.Count * 2);
foreach (object itemKeyObj in parameters.Keys)
{
string itemKey = itemKeyObj?.ToString();
if (itemKey != null)
{
var itemValues = parameters.GetValues(itemKey);
if (itemValues != null)
{
foreach (var itemValue in itemValues)
{
if (!string.IsNullOrEmpty(itemValue))
{
pairs.Add(string.Format("{0}={1}", Uri.EscapeDataString(itemKey), Uri.EscapeDataString(itemValue)));
}
}
}
}
}
return string.Join("&", pairs.ToArray());
}
public static string GetUrlString(string baseUrl, ICollection<KeyValuePair<string, string>> parameters)
{
if (parameters != null && parameters.Count > 0)
{
string queryString = GetUrlQueryString(parameters);
if (!string.IsNullOrEmpty(queryString))
{
StringBuilder builder = new StringBuilder(baseUrl.Length + queryString.Length + 1);
builder.Append(baseUrl);
builder.Append("?");
builder.Append(queryString);
return builder.ToString();
}
}
return baseUrl;
}
public static string GetUrlString(string baseUrl, NameValueCollection parameters)
{
if (parameters != null && parameters.Count > 0)
{
string queryString = GetUrlQueryString(parameters);
if (!string.IsNullOrEmpty(queryString))
{
StringBuilder builder = new StringBuilder(baseUrl.Length + queryString.Length + 1);
builder.Append(baseUrl);
builder.Append("?");
builder.Append(queryString);
return builder.ToString();
}
}
return baseUrl;
}
}
}
这段代码是一个用于处理URL查询参数的C#工具类,主要提供解析和构建URL的功能。以下是其核心内容的详细介绍:
---
### **主要功能**
1. **解析URL参数**
- **`GetQueryDictionary`**: 将URL的查询参数解析为`Dictionary<string, string>`,处理重复键时会覆盖,支持大小写敏感/不敏感。
- **`GetQueryCollection`**: 将URL的查询参数解析为`NameValueCollection`,允许重复键和多个值,适合需要保留多值参数的场景。
2. **构建URL查询字符串**
- **`GetUrlQueryString`**: 从键值对集合或`NameValueCollection`生成URL编码的查询字符串(如`key1=val1&key2=val2`)。
- **`GetUrlString`**: 将基础URL与参数拼接成完整的URL(如`http://example.com?key=val`)。
---
### **关键实现细节**
1. **参数解析逻辑**
- 通过定位第一个`?`分割URL的基地址和查询参数。
- 使用`Split('&')`分割键值对,处理值中包含的`=`符号(如`key=a=b`解析为`key="a=b"`)。
- 对键和值进行URL解码(`Uri.UnescapeDataString`)。
2. **特殊处理**
- **空值处理**:形如`key=`的参数解析为`key: ""`,构建时若值为空则跳过。
- **无值键处理**:形如`key`的参数解析为`key: null`。
- **基地址存储**:通过`baseUrlKey`参数将`?`前的URL部分存入结果(如`baseUrlKey: "url"`会添加`url: "http://example.com"`)。
3. **大小写控制**
- 通过`StringComparer`实现键的大小写敏感/不敏感比较。
---
### **潜在问题与注意事项**
1. **URL拼接限制**
- 若`baseUrl`已包含查询参数或哈希(`#`),拼接时可能出错(如`http://example.com?old=1`拼接后变为`http://example.com?old=1?new=2`)。
2. **空值不一致性**
- 解析时接受空值(`key=`),但构建时忽略空值,可能导致数据丢失。
3. **分隔符支持**
- 仅支持`&`作为参数分隔符,不处理`;`等其他分隔符。
4. **重复键处理**
- `Dictionary`会覆盖重复键,`NameValueCollection`会合并多个值为逗号分隔的字符串。
---
### **示例用法**
```csharp
// 解析URL参数
var url = "https://example.com/path?name=Alice&age=30";
var dict = UrlHelper.GetQueryDictionary(url, "baseUrl", ignoreCase: true);
// dict包含:["baseUrl": "https://example.com/path", "name": "Alice", "age": "30"]
// 构建URL
var parameters = new NameValueCollection { { "q", "test" }, { "page", "2" } };
string fullUrl = UrlHelper.GetUrlString("https://example.com", parameters);
// 输出:https://example.com?q=test&page=2
```
---
### **总结**
该代码提供了一套便捷的URL参数解析与构建工具,适用于需要操作查询字符串的场景,需根据需求选择`Dictionary`或`NameValueCollection`以应对重复键问题。