Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
dotNET Platform
runtime
提交
09d83464
R
runtime
项目概览
dotNET Platform
/
runtime
11 个月 前同步成功
通知
1
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
runtime
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
未验证
提交
09d83464
编写于
3月 31, 2022
作者:
M
Maryam Ariyan
提交者:
GitHub
3月 31, 2022
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Makes GetChildKeys more efficient (#67186)
上级
018b85a3
变更
3
隐藏空白更改
内联
并排
Showing
3 changed file
with
121 addition
and
23 deletion
+121
-23
src/libraries/Microsoft.Extensions.Configuration/src/ConfigurationKeyComparer.cs
....Extensions.Configuration/src/ConfigurationKeyComparer.cs
+47
-23
src/libraries/Microsoft.Extensions.Configuration/tests/ConfigurationPathComparerTest.cs
...ions.Configuration/tests/ConfigurationPathComparerTest.cs
+16
-0
src/libraries/Microsoft.Extensions.Configuration/tests/ConfigurationTest.cs
...osoft.Extensions.Configuration/tests/ConfigurationTest.cs
+58
-0
未找到文件。
src/libraries/Microsoft.Extensions.Configuration/src/ConfigurationKeyComparer.cs
浏览文件 @
09d83464
...
...
@@ -11,7 +11,7 @@ namespace Microsoft.Extensions.Configuration
/// </summary>
public
class
ConfigurationKeyComparer
:
IComparer
<
string
>
{
private
static
readonly
string
[]
_keyDelimiterArray
=
new
[]
{
ConfigurationPath
.
KeyDelimiter
}
;
private
const
char
KeyDelimiter
=
':'
;
/// <summary>
/// The default instance.
...
...
@@ -29,29 +29,61 @@ public class ConfigurationKeyComparer : IComparer<string>
/// <returns>Less than 0 if x is less than y, 0 if x is equal to y and greater than 0 if x is greater than y.</returns>
public
int
Compare
(
string
?
x
,
string
?
y
)
{
string
[]
xParts
=
x
?.
Split
(
_keyDelimiterArray
,
StringSplitOptions
.
RemoveEmptyEntries
)
??
Array
.
Empty
<
string
>();
string
[]
yParts
=
y
?.
Split
(
_keyDelimiterArray
,
StringSplitOptions
.
RemoveEmptyEntries
)
??
Array
.
Empty
<
string
>();
ReadOnlySpan
<
char
>
xSpan
=
x
.
AsSpan
();
ReadOnlySpan
<
char
>
ySpan
=
y
.
AsSpan
();
xSpan
=
SkipAheadOnDelimiter
(
xSpan
);
ySpan
=
SkipAheadOnDelimiter
(
ySpan
);
// Compare each part until we get two parts that are not equal
for
(
int
i
=
0
;
i
<
Math
.
Min
(
xParts
.
Length
,
yParts
.
Length
);
i
++
)
while
(!
xSpan
.
IsEmpty
&&
!
ySpan
.
IsEmpty
)
{
x
=
xParts
[
i
];
y
=
yParts
[
i
];
int
xDelimiterIndex
=
xSpan
.
IndexOf
(
KeyDelimiter
);
int
yDelimiterIndex
=
ySpan
.
IndexOf
(
KeyDelimiter
);
int
compareResult
=
Compare
(
xDelimiterIndex
==
-
1
?
xSpan
:
xSpan
.
Slice
(
0
,
xDelimiterIndex
),
yDelimiterIndex
==
-
1
?
ySpan
:
ySpan
.
Slice
(
0
,
yDelimiterIndex
));
if
(
compareResult
!=
0
)
{
return
compareResult
;
}
int
value1
=
0
;
int
value2
=
0
;
xSpan
=
xDelimiterIndex
==
-
1
?
default
:
SkipAheadOnDelimiter
(
xSpan
.
Slice
(
xDelimiterIndex
+
1
));
ySpan
=
yDelimiterIndex
==
-
1
?
default
:
SkipAheadOnDelimiter
(
ySpan
.
Slice
(
yDelimiterIndex
+
1
));
}
bool
xIsInt
=
x
!=
null
&&
int
.
TryParse
(
x
,
out
value1
);
bool
yIsInt
=
y
!=
null
&&
int
.
TryParse
(
y
,
out
value2
);
return
xSpan
.
IsEmpty
?
(
ySpan
.
IsEmpty
?
0
:
-
1
)
:
1
;
static
ReadOnlySpan
<
char
>
SkipAheadOnDelimiter
(
ReadOnlySpan
<
char
>
a
)
{
while
(!
a
.
IsEmpty
&&
a
[
0
]
==
KeyDelimiter
)
{
a
=
a
.
Slice
(
1
);
}
return
a
;
}
static
int
Compare
(
ReadOnlySpan
<
char
>
a
,
ReadOnlySpan
<
char
>
b
)
{
#if NETCOREAPP
bool
aIsInt
=
int
.
TryParse
(
a
,
out
int
value1
);
bool
bIsInt
=
int
.
TryParse
(
b
,
out
int
value2
);
#else
bool
aIsInt
=
int
.
TryParse
(
a
.
ToString
(),
out
int
value1
);
bool
bIsInt
=
int
.
TryParse
(
b
.
ToString
(),
out
int
value2
);
#endif
int
result
;
if
(!
xIsInt
&&
!
y
IsInt
)
if
(!
aIsInt
&&
!
b
IsInt
)
{
// Both are strings
result
=
string
.
Compare
(
x
,
y
,
StringComparison
.
OrdinalIgnoreCase
);
result
=
a
.
CompareTo
(
b
,
StringComparison
.
OrdinalIgnoreCase
);
}
else
if
(
xIsInt
&&
y
IsInt
)
else
if
(
aIsInt
&&
b
IsInt
)
{
// Both are int
result
=
value1
-
value2
;
...
...
@@ -59,19 +91,11 @@ public int Compare(string? x, string? y)
else
{
// Only one of them is int
result
=
x
IsInt
?
-
1
:
1
;
result
=
a
IsInt
?
-
1
:
1
;
}
if
(
result
!=
0
)
{
// One of them is different
return
result
;
}
return
result
;
}
// If we get here, the common parts are equal.
// If they are of the same length, then they are totally identical
return
xParts
.
Length
-
yParts
.
Length
;
}
}
}
src/libraries/Microsoft.Extensions.Configuration/tests/ConfigurationPathComparerTest.cs
浏览文件 @
09d83464
...
...
@@ -14,6 +14,8 @@ public void CompareWithNull()
ComparerTest
(
null
,
null
,
0
);
ComparerTest
(
null
,
"a"
,
-
1
);
ComparerTest
(
"b"
,
null
,
1
);
ComparerTest
(
null
,
"a:b"
,
-
1
);
ComparerTest
(
null
,
"a:b:c"
,
-
1
);
}
[
Fact
]
...
...
@@ -32,6 +34,20 @@ public void CompareWithDifferentLengths()
ComparerTest
(
"aa"
,
"a"
,
1
);
}
[
Fact
]
public
void
CompareWithEmpty
()
{
ComparerTest
(
":"
,
""
,
0
);
ComparerTest
(
":"
,
"::"
,
0
);
ComparerTest
(
null
,
""
,
0
);
ComparerTest
(
":"
,
null
,
0
);
ComparerTest
(
"::"
,
null
,
0
);
ComparerTest
(
" : : "
,
null
,
1
);
ComparerTest
(
"b: :a"
,
"b::a"
,
-
1
);
ComparerTest
(
"b:\t:a"
,
"b::a"
,
-
1
);
ComparerTest
(
"b::a: "
,
"b::a:"
,
1
);
}
[
Fact
]
public
void
CompareWithLetters
()
{
...
...
src/libraries/Microsoft.Extensions.Configuration/tests/ConfigurationTest.cs
浏览文件 @
09d83464
...
...
@@ -59,6 +59,64 @@ public void LoadAndCombineKeyValuePairsFromDifferentConfigurationProviders()
Assert
.
Null
(
config
[
"NotExist"
]);
}
[
Fact
]
private
void
GetChildKeys_CanChainEmptyKeys
()
{
var
input
=
new
Dictionary
<
string
,
string
>()
{
};
for
(
int
i
=
0
;
i
<
1000
;
i
++)
{
input
.
Add
(
new
string
(
' '
,
i
),
string
.
Empty
);
}
IConfigurationRoot
configurationRoot
=
new
ConfigurationBuilder
()
.
Add
(
new
MemoryConfigurationSource
{
InitialData
=
input
})
.
Build
();
var
chainedConfigurationSource
=
new
ChainedConfigurationSource
{
Configuration
=
configurationRoot
,
ShouldDisposeConfiguration
=
false
,
};
var
chainedConfiguration
=
new
ChainedConfigurationProvider
(
chainedConfigurationSource
);
IEnumerable
<
string
>
childKeys
=
chainedConfiguration
.
GetChildKeys
(
new
string
[
0
],
null
);
Assert
.
Equal
(
1000
,
childKeys
.
Count
());
Assert
.
Equal
(
string
.
Empty
,
childKeys
.
First
());
Assert
.
Equal
(
999
,
childKeys
.
Last
().
Length
);
}
[
Fact
]
private
void
GetChildKeys_CanChainKeyWithNoDelimiter
()
{
var
input
=
new
Dictionary
<
string
,
string
>()
{
};
for
(
int
i
=
1000
;
i
<
2000
;
i
++)
{
input
.
Add
(
i
.
ToString
(),
string
.
Empty
);
}
IConfigurationRoot
configurationRoot
=
new
ConfigurationBuilder
()
.
Add
(
new
MemoryConfigurationSource
{
InitialData
=
input
})
.
Build
();
var
chainedConfigurationSource
=
new
ChainedConfigurationSource
{
Configuration
=
configurationRoot
,
ShouldDisposeConfiguration
=
false
,
};
var
chainedConfiguration
=
new
ChainedConfigurationProvider
(
chainedConfigurationSource
);
IEnumerable
<
string
>
childKeys
=
chainedConfiguration
.
GetChildKeys
(
new
string
[
0
],
null
);
Assert
.
Equal
(
1000
,
childKeys
.
Count
());
Assert
.
Equal
(
"1000"
,
childKeys
.
First
());
Assert
.
Equal
(
"1999"
,
childKeys
.
Last
());
}
[
Fact
]
public
void
CanChainConfiguration
()
{
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录