ControlCollection 中的重复字符串索引是否可能?它是如何工作的?
Is duplicate string index in ControlCollection possible? And how does it work?
我在 WinForms C# 中开始一个小项目,有这样的东西:
UserControl uc1 = new UserControl();
UserControl uc2 = new UserControl();
mainPanel.Controls.Add(uc1);
mainPanel.Controls.Add(uc2);
Console.WriteLine(mainPanel.Controls["UserControl"].Width);
知道mainPanel.Controls
是集合,怎么会出现UserControl - class uc1
和uc2
的名称 -可以作为索引吗?
如果是这样,集合中的这 2 个元素具有相同的索引,即 UserControl,这甚至可能吗?或者这是 .NET Framework 的特殊之处?
如果我们看一下下面的代码,会发生什么
var uc1 = new UserControl();
var uc2 = new UserControl();
//We have to set the name, because one is not assigned automatically via code, only when added via Designer
uc1.Name = "notUnique";
uc2.Name = "notUnique";
//We add unique text values so that we can distinguish them uniquely for the purpose of this test
uc1.Text = "uc1";
uc2.Text = "uc2";
panel1.Controls.Add(uc1);
panel1.Controls.Add(uc2);
var control = panel1.Controls["notUnique"];
结果是control
是uc1
。
但是如果我们交换控件的添加,那么我们先将 uc2
添加到集合中
panel1.Controls.Add(uc2);
panel1.Controls.Add(uc1);
var control = panel1.Controls["notUnique"];
那么在这种情况下 control
= uc2
那么很明显,索引 return 是它找到的第一个匹配项(如果 none 匹配则为空)。
有趣的是,这意味着如果您还使用键删除控件,它将删除它从集合中找到的第一个控件。
panel1.Controls.RemoveByKey("notUnique");
您假设控件的名称必须是唯一的。但实际上并非如此,在 Control 的文档中,名称 属性 并未声明必须是唯一的。
现在有人可能会争辩说,在文档中使用了术语“key”,这是一个错误,但这需要与 Microsoft 讨论!我怀疑他们会声明它 按设计工作。 (如果他们更改代码,我会看到很多损坏的代码!)
同样有趣的是,如果你看一下方法 ControlCollection.Find
public System.Windows.Forms.Control[] Find (string key, bool searchAllChildren);
然后你会看到这将 return 一个数组。
在这个合集
中是可能的
如果您查看 ControlCollection 的 the source code,您会看到采用字符串的索引器:
public virtual Control this[string key] {
get {
// We do not support null and empty string as valid keys.
if (String.IsNullOrEmpty(key)) {
return null;
}
// Search for the key in our collection
int index = IndexOfKey(key);
if (IsValidIndex(index)) {
return this[index];
}
else {
return null;
}
}
}
控件保存在(数组)列表中,IndexOfKey 用于查找给定名称的第一个索引:
public virtual int IndexOfKey(String key) {
// Step 0 - Arg validation
if (String.IsNullOrEmpty(key)) {
return -1; // we dont support empty or null keys.
}
// step 1 - check the last cached item
if (IsValidIndex(lastAccessedIndex))
{
if (WindowsFormsUtils.SafeCompareStrings(this[lastAccessedIndex].Name, key, /* ignoreCase = */ true)) {
return lastAccessedIndex;
}
}
// step 2 - search for the item
for (int i = 0; i < this.Count; i ++) {
if (WindowsFormsUtils.SafeCompareStrings(this[i].Name, key, /* ignoreCase = */ true)) {
lastAccessedIndex = i;
return i;
}
}
// step 3 - we didn't find it. Invalidate the last accessed index and return -1.
lastAccessedIndex = -1;
return -1;
}
此代码中没有任何唯一性约束..它只是“找到第一个添加该字符串的人”
旁注;查看这样的旧代码 (ArrayList) 并考虑现在我们拥有更强大的集合、LINQ、字典、命名参数时如何编写它是很有趣的。显然这是一种优化,MS 希望人们在循环中重复使用字符串查找等,所以他们保留最后使用的字符串并比较这个字符串以查看.. Whicj 反过来我猜意味着为了最好的资源使用,如果你知道你要通过相同的字符串重复访问控件(在循环中?)而是通过数字索引访问它..
我在 WinForms C# 中开始一个小项目,有这样的东西:
UserControl uc1 = new UserControl();
UserControl uc2 = new UserControl();
mainPanel.Controls.Add(uc1);
mainPanel.Controls.Add(uc2);
Console.WriteLine(mainPanel.Controls["UserControl"].Width);
知道mainPanel.Controls
是集合,怎么会出现UserControl - class uc1
和uc2
的名称 -可以作为索引吗?
如果是这样,集合中的这 2 个元素具有相同的索引,即 UserControl,这甚至可能吗?或者这是 .NET Framework 的特殊之处?
如果我们看一下下面的代码,会发生什么
var uc1 = new UserControl();
var uc2 = new UserControl();
//We have to set the name, because one is not assigned automatically via code, only when added via Designer
uc1.Name = "notUnique";
uc2.Name = "notUnique";
//We add unique text values so that we can distinguish them uniquely for the purpose of this test
uc1.Text = "uc1";
uc2.Text = "uc2";
panel1.Controls.Add(uc1);
panel1.Controls.Add(uc2);
var control = panel1.Controls["notUnique"];
结果是control
是uc1
。
但是如果我们交换控件的添加,那么我们先将 uc2
添加到集合中
panel1.Controls.Add(uc2);
panel1.Controls.Add(uc1);
var control = panel1.Controls["notUnique"];
那么在这种情况下 control
= uc2
那么很明显,索引 return 是它找到的第一个匹配项(如果 none 匹配则为空)。
有趣的是,这意味着如果您还使用键删除控件,它将删除它从集合中找到的第一个控件。
panel1.Controls.RemoveByKey("notUnique");
您假设控件的名称必须是唯一的。但实际上并非如此,在 Control 的文档中,名称 属性 并未声明必须是唯一的。
现在有人可能会争辩说,在文档中使用了术语“key”,这是一个错误,但这需要与 Microsoft 讨论!我怀疑他们会声明它 按设计工作。 (如果他们更改代码,我会看到很多损坏的代码!)
同样有趣的是,如果你看一下方法 ControlCollection.Find
public System.Windows.Forms.Control[] Find (string key, bool searchAllChildren);
然后你会看到这将 return 一个数组。
在这个合集
中是可能的如果您查看 ControlCollection 的 the source code,您会看到采用字符串的索引器:
public virtual Control this[string key] {
get {
// We do not support null and empty string as valid keys.
if (String.IsNullOrEmpty(key)) {
return null;
}
// Search for the key in our collection
int index = IndexOfKey(key);
if (IsValidIndex(index)) {
return this[index];
}
else {
return null;
}
}
}
控件保存在(数组)列表中,IndexOfKey 用于查找给定名称的第一个索引:
public virtual int IndexOfKey(String key) {
// Step 0 - Arg validation
if (String.IsNullOrEmpty(key)) {
return -1; // we dont support empty or null keys.
}
// step 1 - check the last cached item
if (IsValidIndex(lastAccessedIndex))
{
if (WindowsFormsUtils.SafeCompareStrings(this[lastAccessedIndex].Name, key, /* ignoreCase = */ true)) {
return lastAccessedIndex;
}
}
// step 2 - search for the item
for (int i = 0; i < this.Count; i ++) {
if (WindowsFormsUtils.SafeCompareStrings(this[i].Name, key, /* ignoreCase = */ true)) {
lastAccessedIndex = i;
return i;
}
}
// step 3 - we didn't find it. Invalidate the last accessed index and return -1.
lastAccessedIndex = -1;
return -1;
}
此代码中没有任何唯一性约束..它只是“找到第一个添加该字符串的人”
旁注;查看这样的旧代码 (ArrayList) 并考虑现在我们拥有更强大的集合、LINQ、字典、命名参数时如何编写它是很有趣的。显然这是一种优化,MS 希望人们在循环中重复使用字符串查找等,所以他们保留最后使用的字符串并比较这个字符串以查看.. Whicj 反过来我猜意味着为了最好的资源使用,如果你知道你要通过相同的字符串重复访问控件(在循环中?)而是通过数字索引访问它..