一、作业问题
1、问:listbox1.items[i]返回的object是指的字符串吗?
答:items是真正的对象集合,在Add时加的是Person对象p,则里面的item就是Person对象p。
但是,在listbox1显示框中显示的,并不是p,而是p.ToString()。若不加ToString()
会默认使用该方法。若不重写将是"命名空间.类型名"。因此一般在Person类中重写字符串
方法,以符合程序设计方式。
因此,item或items[index]直接作原加入的对象进行使用,必要时进行显式转换。
2、问:退出方法,窗体,程序有哪些方法,有什么区别?
答:(1)This.Close()
此方法是窗体对象的一个成员方法,用于关闭当前窗体。它会触发窗体的FormClosing
和FormClosed事件,并且在关闭前会执行窗体上的一些清理工作。
注意,使用this.Close()只能关闭当前窗体,如果想退出整个应用程序,还需要关闭其
他可能存在的窗体。
(2)Application.Exit()
这个方法是System.Windows.Forms.Application类的一个静态方法,用于退出应用程序。
它会退出应用程序的消息循环,并且在退出前触发ApplicationExit事件。
使用Application.Exit()可以确保关闭所有打开的窗体,并且退出应用程序。
(3)return语句
在事件处理方法中使用return语句可以提前结束该方法的执行。如果事件处理方法是一
个事件的最后一个处理方法,并且没有其他事件侦听该事件,那么使用return语句可以达到
关闭窗体或退出应用程序的效果。但如果有其他事件侦听该事件,return语句只会结束当前
事件处理方法的执行,并不会关闭窗体或退出应用程序。
(4)Environment.Exit(0)
这个方法是System.Environment类的一个静态方法,用于立即终止应用程序并返回指定
的退出代码。它不会触发任何清理工作,也不会触发任何事件。通常这种方式向系统或其它
调用程序传递退出代码,用0表示正常退出,用非零表示异常退出。
一般情况下,建议使用Application.Exit()而不是Environment.Exit()。
(5)this.Hide()
这个方法用于隐藏当前窗体,但窗体实际上并没有关闭。如果需要再次显示窗体,可以
使用this.Show()方法。
3、问:List<T>能保存二维数据吗?例如List<T,Z>。
答:不能.
在C#, List<T> 类型只能保存一维数据,即T类型的单个值。它不支持直接保存二维数
据。如果你需要保存二维数据,可以考虑使用多维数组或者嵌套的集合类型。
(1)多维数组
cs
int[,] twoDimensionalArray = new int[3, 3];
twoDimensionalArray[0, 0] = 1;
twoDimensionalArray[0, 1] = 2;
(2)嵌套的集合类型
嵌套的集合类型是指将一个集合作为另一个集合的元素来构建更复杂的数据结构。这可
以通过嵌套使用标准集合类或自定义集合类来实现。
(2.1)List<List<T>>
这是一个嵌套的列表,用于存储具有多个层级的元素。例如,List<List<int>> 表示一
个二维整数数组。它适用于表示矩阵或二维表格等结构。
使用场景:当需要使用二维或多维的数据结构时,可以使用嵌套的列表。例如,表示棋
盘上的方格、存储多个学生的分数等。
注意:当访问嵌套列表中的元素时,需要使用两个索引来指定元素的位置。例如,访问
二维数组中的元素可以使用 list[i][j] 的方式。在添加或删除元素时,需要小心对嵌套列
表的索引进行管理,以避免出现越界或逻辑错误。
cs
List<List<int>> list = new List<List<int>>();
List<int> list0 = new List<int>() { 0, 1, 2 };
List<int> list1 = new List<int>() { 3, 4, 5 };
List<int> list2 = new List<int>() { 6, 7, 8 };
list.Add(list0);
list.Add(list1);
list.Add(list2);
Console.WriteLine(list[1][1].ToString());//4
一般设计时内层list最好设计为等长,以便循环获取或设置。否则,有时可能越界异常
(2.2)Dictionary<T1, List<T2>>
这是一个将键值对中的值作为列表的字典。它适用于需要按键进行分组的场景。
使用场景:当需要对数据进行分组,并且每个组可以包含多个元素时,可以使用这样的
嵌套字典。
注意:当添加新的元素时,需要先检查字典中是否存在对应的键,如果不存在则创建一
个新的列表,并将元素加入到列表中。当访问嵌套字典中的元素时,先访问键的值(即列
表),然后再通过索引访问列表中的元素。
cs
Dictionary<string, List<int>> grades = new Dictionary<string, List<int>>();
List<int> tom = new List<int>() { 88, 89, 90 };
List<int> john = new List<int>() { 90, 93, 78 };
grades.Add("Tom", tom);
grades.Add("John", john);
Console.WriteLine(grades["Tom"][1]);//89
上面是存储学生语数成绩的结构。注意唯一性与长度。
(2.3)HashSet<HashSet<T>>
这是一个嵌套的哈希集合,用于存储唯一的元素集合。
使用场景:当需要存储多个唯一的集合,并且每个集合可能包含多个唯一元素时,可以
使用嵌套的哈希集合。
注意:当添加新的元素时,需要先检查嵌套的哈希集合中是否存在对应的集合,如果不
存在则创建一个新的集合,并将元素加入到集合中。当访问嵌套哈希集合中的元素时,先访
问外层集合,然后再通过迭代方式访问内层集合中的元素。
cs
HashSet<HashSet<int>> set = new HashSet<HashSet<int>>();
HashSet<int> set0 = new HashSet<int>() { 0, 1, 2 };
HashSet<int> set1 = new HashSet<int>() { 3, 4, 5 };
HashSet<int> set2 = new HashSet<int>() { 6, 7, 7 };//a
set.Add(set0);
set.Add(set1);
set.Add(set2);
Console.WriteLine(set.ElementAt(2).ElementAt(1));//7
HashSet<List<int>> hs = new HashSet<List<int>>();
List<int> list0 = new List<int>() { 0, 1, 2 };
List<int> list1 = new List<int>() { 3, 4, 5 };
hs.Add(list0);
hs.Add(list1);
Console.WriteLine(hs.ElementAt(1)[1]);//4
上面a不会报错,凡是重复的,只会存储一个样本。若set1也为{0,1,2}则上面实际是只有
set0存储了,set1因重复不会报错也不会存储,set1为{2,1,0}也是重复的。若为{0,1,2,3}则
不是重复的。
由于嵌套带来了复杂性,需要注意:
a.嵌套集合的性能:
嵌套集合可能会带来额外的性能开销,特别是在插入和删除元素时。要谨慎使用嵌套集
合,并注意性能考虑。
b.数据一致性:
当修改嵌套集合中的元素时,需要确保数据保持一致。即使在嵌套的集合中进行了更改,
也应该反映在外层集合中。
c.错误处理:
在使用嵌套集合时,需要小心处理索引、边界等可能导致错误的情况,以避免出现异常
或逻辑错误。
所以,嵌套的集合类型可以用于构建复杂的数据结构,但使用它们时需要小心处理,注
意数据一致性和性能问题,并小心处理可能导致错误的情况。
4、问:listbox1.items[listbox1.selectedindex]与listbox1.selecteditem有什么区别?
答:(1)访问方式:
前者是通过索引来访问 Items 集合,需要指定索引位置。
后者直接返回当前选中的项对象,无需指定索引。
(2)可读写性:
前者是可读写的。可以读取或修改 ListBox 中特定索引位置的项。
后者是只读属性,只能读取当前选中的项对象,无法直接修改其引用。
因此在修改listbox1中选中项时,使用前者。
二、Xpath路径表达式
1、XPath路径表达式(类似正则表达式)
XPath 是一种用于在 XML 文档中定位节点的表达式语言。在 C# 的 XmlDocument(或
XElement)中,可以使用 XPath 表达式来选择并提取符合条件的节点。
XPath 表达式由一系列路径和条件组成,用于描述节点的层次结构和属性值。
(1)路径表达式:
/:从根节点开始选择。
例: /AAA,/AAA/BBB,/AAA/BBB/CCC
//:选择任意位置的节点。
例://BBB,//BBB/CCC,//CCC/DDD/EEE
elementName:选择指定名称的元素节点。例:上面的元素名AAA之类
*:选择任意名称的元素节点。
例:/AAA/BBB/*,//CCC/*,/*/*/*/BBB三个层次后面的BBB元素节点
//*所有元素节点,//AA所有AA元素节点,
/AAA/BBB[1]节点AAA下BBB所有元素节点的第一个。
/AAA/BBB[last()]节点AAA下BBB所有元素节点的最后一个。
注意:XML区分大小写,因此xpath也是区别大小写的
(2)条件表达式:
@attributeName='value'\]:选择具有指定属性名和属性值的节点。
\[@attributeName\]:选择具有指定属性名的节点。
注意:加上@表示属性,不加表示元素。
例://@style选择所有属性为style的结点(属性也是结点,又如//@id)
//BBB\[@id\]所有含有id属性的BBB元素结点(注意重点是元素,上一行重点是属性)
//BBB\[@name\]所有含有name属性的BBB元素结点(重点是元素)
//BBB\[@\*\]所有含有属性的BBB元素结点(无属性的排除)
//BBB\[not(@\*)\]所有不能有任何属性的BBB元素结点
//BBB\[@id='b1'\]所有且有属性id且值为'b1'的BBB元素结点
//BBB\[normalize-space(@name)='bbb'\]去值两端空格类似trim
//\*\[count(BBB)=2\]选择含有两个BBB子元素的元素(父元素)
//\*\[count(\*)=2\]只包含两个子元素的元素结点(父元素)
//\*\[count(\*)=3\].....三...
name()函数返回元素的名称;
starts-with(,)函数在该函数的第一个参数字符串是以第二个参数字符开始的情况返
回true;
contains(,)函数当其第一个字符串参数包含有第二个字符串参数时返回true。
//\*\[name()='BBB'\]所有名称为BBB的元素,等价=//BBB
//\*\[starts-with(name(),'B')\]所有名称以B开头的元素
//\*\[contains(name(),'C')\]所有名称中含有C的元素
string-length()函数返回字符串的字符数,你应该用\<替代\<,用\>替代\>
//\*\[string-length(name())=3\]所有名字长度为3的元素
//\*\[string-length(name())\<3\]所有名字长度小于3的元素
//\*\[string-length(name())\>3\]所有名字长度大于3的元素
\|多个路径进行合并。
//CCC\|//BBB 所有CCC与BBB的元素合集
/AAA/EEE\|//BBB 所有BBB与AAA下面EEE结点的合集
/AAA/EEE\|//DDD/CCC\|/AAA\|//BBB 可以合并的路径数目没有限制
\[index\]表示同类节点的第index个(从1开始)
//CCC/p\[1\] 所有CCC结点后p结点中第一个p结点
注意:结点与节点都表示同样的意思node.
**(3)轴轶函数:**
ancestor:::选择当前节点的所有祖先节点。总是包含根节点,除非上下文节点就是根
节点。注意,是直系祖先,旁系不算,例如父亲的兄弟不算
parent:::选择当前节点的父节点。
child:::选择当前节点的所有子节点。
descendant:::选择当前节点的所有后代节点。
following-sibling:::包含上下文节点之后的所有兄弟节点.
注意:只是后面跟随的兄弟结点,前面的兄弟结点不包括。
preceding-sibling:::跟上面相对,是该结点之前的所有兄弟结点(不含本身)
following:::包含同一文档按文档顺序位于上下文节点之后的所有节点,除了祖先节点,
属性节点和命名空间节点。
preceding:::与上面相对,前面的兄弟及堂姪节点
descendant-or-self:::自身及其所有后代节点(不包含自身的兄弟结点)
ancestor-or-self:::自身及其所有祖先节点(不包含自身的兄弟结点
self:::自身
轴可以看作是一种在XML文档中沿着路径定位结点的方式,可以根据当前结点的关系找
到其他相关的结点。
可以把轴理解为路标,每一个关键处都有一个路标指明下一步走的方向。轴默认就是
child即当前节点的子节点,默认路标指向下一个子节点,如/AAA即/child::AAA表示根/节
点下面的子节点AAA,//BBB/parent::CCC表示当前BBB节点的父节点BBB。
child轴(axis)包含上下文节点的子元素,作为默认的轴,可以忽略不写。
/AAA 等价于/child::AAA
/descendant::\*选择文档根元素的所有后代,即所有元素被选择
//DDD/parent::\* 所有DDD元素的父节点合集(从DDD转向父节点)
/AAA/BBB/DDD/CCC/EEE/ancestor::\* 所有祖先结点(从EEE转向祖先,不含EEE,不含
祖先中的兄弟元素)直系祖先
//fff/ancestor::\* 所有FFF元素的祖先节点
/aaa/bbb/following-sibling::\* 指定bbb后面的所有兄弟节点(不含bbb,跟随同级)
//ccc/following-sibling::\* 所有ccc后面的所有兄弟结点(不含ccc)
//aaa/xxx/preceding-sibling::\* xxx前面所有的兄弟结点
//ccc/preceding-sibling::\*
//xxx/following::\* xxx后面的所有兄弟节点及子节点(不含本身xxx)
//AAA/XXX/preceding::\* XXX前面所有兄弟及其子节点
//aaa/xxx/descendant-or-self::\* xxx自身及其所有后代节点
//fff/descendant-or-selft::\* 所有fff结点及其所有后代节点
//zzz/yyy/xxx/sss/ancestor-or-self::\*
//ggg/ancestor::\*
//xxx/self::\*
//GGG/ancestor::\*\|//GGG/descendant::\*\|GGG/following::\*\|//GGG/preceding::\*
\|//GGG/self::\*
**(4)运算函数**
div运算符做浮点除法运算
mod运算符做求余运算
floor函数返回不大于参数的最大整数(趋近于正无穷)
ceiling返回不小于参数的最小整数(趋近于负无穷)
//BBB\[position()mod 2 =0\]选择偶数位置的BBB元素
注意:
在XPath中,斜杠(/)表示文档根节点,而不是文档本身。斜杠后面的节点表示文档根
节点的直接子节点。
如果你使用XPath表达式 "/aaa",它表示选择文档根节点下名为 "aaa" 的直接子节点。
这个节点可以是元素、属性、命名空间等。
请注意,XPath中的斜杠表示层级关系,而不是路径的开始或结束。因此,斜杠前面没有
节点时,它表示文档根节点。
如果你想选择文档本身,可以使用点(.)表示当前节点。例如,".//aaa" 表示选择文
档中所有名为 "aaa" 的节点,而不仅仅是文档根节点下的直接子节点。
**问:xpath文档里常说"包含上下文",这是什么意思?**
答:上下文是指在执行XPath表达式时所处的环境或位置。上下文通常是一个节点集合,可
以是整个文档、某个元素的子节点集合,或者是其他节点的集合。
在XPath表达式中,使用.表示当前节点,使用..表示当前节点的父节点。这些符号是
相对于上下文节点进行定位的。
**2、XmlDocument有哪些方法来操作xpath?**
XmlDocument中,可以使用SelectNodes()方法和SelectSingleNode()方法来执行XPath
查询并获取符合条件的节点。
```cs
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load("example.xml");
XmlNodeList nodeList = xmlDoc.SelectNodes("//name");// 使用 XPath 选择所有 name 元素节点
foreach (XmlNode node in nodeList)
{
Console.WriteLine(node.InnerText);
}
// 使用 XPath 选择具有 id 属性值为 "I8" 的 element 元素节点
XmlNode elementNode = xmlDoc.SelectSingleNode("//element[@id='I8']");
if (elementNode != null)
{
string name = elementNode.SelectSingleNode("name").InnerText;
Console.WriteLine("Name: " + name);
}
```
(1)SelectNodes方法:
该方法返回一个XmlNodeList对象,包含满足XPath表达式的所有节点。可以使用该方法
来定位多个元素。例如,使用XPath表达式"//book"可以定位所有的书籍元素。
(2)SelectSingleNode方法:
该方法返回一个XmlNode对象,包含满足XPath表达式的第一个节点。可以使用该方法来
定位单个元素。例如,使用XPath表达式"title"可以定位书籍元素下的标题元素。
例:xml文件:
```XML