-2

我在 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是一个集合,为什么UserControluc1 -和的类名uc2- 可以像索引一样起作用?如果是这样,集合中的这两个元素具有相同的索引,即UserControl,这甚至可能吗?或者这是 .NET Framework 的特殊之处?

4

2 回答 2

2

如果我们看一下下面的代码,会发生什么

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

因此很明显,索引返回它找到的第一个匹配项(如果不匹配,则返回 null)。

有趣的是,这意味着如果您还使用键删除控件,它将删除从集合中找到的第一个控件。

panel1.Controls.RemoveByKey("notUnique");

您假设控件的名称必须是唯一的。但实际上并非如此,并且在 Control 的文档中,Name 属性并未说明必须是唯一的。

现在有人可能会争辩说,正如在文档中使用术语“密钥”一样,这是一个错误,但这是与微软讨论的事情!我怀疑他们会说它按设计工作。(如果他们更改它,我会看到很多损坏的代码!)

同样有趣的是,如果您查看方法ControlCollection.Find

public System.Windows.Forms.Control[] Find (string key, bool searchAllChildren);

然后你会看到这将返回一个数组。

于 2021-08-20T05:10:03.713 回答
0

这个集合中是可能的

如果您查看ControlCollection的源代码,您将看到采用字符串的索引器:

        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)并考虑如何编写它是很有趣的等等,所以他们保留最后使用的字符串并比较这个字符串来查看。我猜想这意味着如果你知道你要通过同一个字符串重复访问一个控件(在一个循环中?)而是通过数字索引访问它..

于 2021-08-20T07:13:23.950 回答