当前位置: 首页 > news >正文

博客社区类网站模板桂林视频网站制作

博客社区类网站模板,桂林视频网站制作,网络规划设计师和中级对比,东营刚刚发生一、作业问题 1、问#xff1a;listbox1.items[i]返回的object是指的字符串吗#xff1f; 答#xff1a;items是真正的对象集合#xff0c;在Add时加的是Person对象p#xff0c;则里面的item就是Person对象p。 但是#xff0c;在listbox1显…一、作业问题 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、问:ListT能保存二维数据吗例如ListT,Z。              答不能.             在C#, ListT 类型只能保存一维数据即T类型的单个值。它不支持直接保存二维数         据。如果你需要保存二维数据可以考虑使用多维数组或者嵌套的集合类型。                      (1)多维数组 int[,] twoDimensionalArray new int[3, 3];twoDimensionalArray[0, 0] 1;twoDimensionalArray[0, 1] 2; (2)嵌套的集合类型             嵌套的集合类型是指将一个集合作为另一个集合的元素来构建更复杂的数据结构。这可         以通过嵌套使用标准集合类或自定义集合类来实现。                      (2.1)ListListT             这是一个嵌套的列表用于存储具有多个层级的元素。例如ListListint 表示一         个二维整数数组。它适用于表示矩阵或二维表格等结构。             使用场景当需要使用二维或多维的数据结构时可以使用嵌套的列表。例如表示棋         盘上的方格、存储多个学生的分数等。             注意当访问嵌套列表中的元素时需要使用两个索引来指定元素的位置。例如访问         二维数组中的元素可以使用 list[i][j] 的方式。在添加或删除元素时需要小心对嵌套列         表的索引进行管理以避免出现越界或逻辑错误。 ListListint list new ListListint();Listint list0 new Listint() { 0, 1, 2 };Listint list1 new Listint() { 3, 4, 5 };Listint list2 new Listint() { 6, 7, 8 };list.Add(list0);list.Add(list1);list.Add(list2);Console.WriteLine(list[1][1].ToString());//4 一般设计时内层list最好设计为等长以便循环获取或设置。否则有时可能越界异常                      (2.2)DictionaryT1, ListT2             这是一个将键值对中的值作为列表的字典。它适用于需要按键进行分组的场景。             使用场景当需要对数据进行分组并且每个组可以包含多个元素时可以使用这样的         嵌套字典。             注意当添加新的元素时需要先检查字典中是否存在对应的键如果不存在则创建一         个新的列表并将元素加入到列表中。当访问嵌套字典中的元素时先访问键的值即列         表然后再通过索引访问列表中的元素。 Dictionarystring, Listint grades new Dictionarystring, Listint();Listint tom new Listint() { 88, 89, 90 };Listint john new Listint() { 90, 93, 78 };grades.Add(Tom, tom);grades.Add(John, john);Console.WriteLine(grades[Tom][1]);//89 上面是存储学生语数成绩的结构。注意唯一性与长度。                      (2.3)HashSetHashSetT             这是一个嵌套的哈希集合用于存储唯一的元素集合。             使用场景当需要存储多个唯一的集合并且每个集合可能包含多个唯一元素时可以         使用嵌套的哈希集合。             注意当添加新的元素时需要先检查嵌套的哈希集合中是否存在对应的集合如果不         存在则创建一个新的集合并将元素加入到集合中。当访问嵌套哈希集合中的元素时先访         问外层集合然后再通过迭代方式访问内层集合中的元素。 HashSetHashSetint set new HashSetHashSetint();HashSetint set0 new HashSetint() { 0, 1, 2 };HashSetint set1 new HashSetint() { 3, 4, 5 };HashSetint set2 new HashSetint() { 6, 7, 7 };//aset.Add(set0);set.Add(set1);set.Add(set2);Console.WriteLine(set.ElementAt(2).ElementAt(1));//7HashSetListint hs new HashSetListint();Listint list0 new Listint() { 0, 1, 2 };Listint list1 new Listint() { 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)条件表达式             [attributeNamevalue]选择具有指定属性名和属性值的节点。             [attributeName]选择具有指定属性名的节点。                          注意加上表示属性不加表示元素。                 例//style选择所有属性为style的结点属性也是结点,又如//id)                 //BBB[id]所有含有id属性的BBB元素结点注意重点是元素上一行重点是属性                 //BBB[name]所有含有name属性的BBB元素结点(重点是元素)                 //BBB[*]所有含有属性的BBB元素结点(无属性的排除                 //BBB[not(*)]所有不能有任何属性的BBB元素结点                 //BBB[idb1]所有且有属性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()函数返回字符串的字符数你应该用lt;替代,用gt;替代                 //*[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         查询并获取符合条件的节点。 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[idI8]);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 version1.0 encodingutf-8 ?schoolstudent id001 position1name许万里/nameage18/age/studentstudent id002 position2name刘万仁/nameage19/age/studentstudent id003 position1name晨微/nameage20/age/studentstudent id004 position1name郎吉祥/nameage21/age/student/school 利用xmldocument使用xpath: XmlDocument xmldoc new XmlDocument();xmldoc.Load(student.xml);XmlNodeList xmlns xmldoc.SelectNodes(//student[id][position1]);foreach (XmlNode n in xmlns){Console.WriteLine(${n.Name},{n.Attributes[id].Value});} 3、XDocumetn中使用xpath的有哪些                      XDocument类提供了三个主要的方法来使用XPath表达式进行元素选择和查询         XPathSelectElement方法             使用XPath表达式选择单个元素。它返回满足XPath条件的第一个元素如果没有匹配的             元素则返回null。         XPathSelectElements方法             使用XPath表达式选择多个元素。它返回一个IEnumerableXElement对象其中包含满             足XPath条件的所有元素。         XPathEvaluate方法             使用XPath表达式对文档进行求值。它返回一个object类型的结果根据XPath表达式的             求值结果的类型可能会有所不同。                          这些方法允许您在XDocument中使用XPath表达式来选择元素或执行XPath查询。请注意         在使用这些方法之前需要导入System.Xml.Linq和System.Xml.XPath命名空间。linq可以         进一步提供谓词、筛选、修改XML文档等功能。          例xml文件: librarybooktitleBook 1/titleauthorAuthor 1/author/bookbooktitleBook 2/titleauthorAuthor 2/author/book/library 使用xpath操作 XDocument xdoc XDocument.Load(book.xml);IEnumerableXElement xeles xdoc.XPathSelectElements(//title);foreach (XElement n in xeles){Console.WriteLine(${n.Name},{n.Value});}XElement xele xdoc.XPathSelectElement(/library/book);Console.WriteLine(xele.Element(title).Value);IEnumerableobject s (IEnumerableobject)xdoc.XPathEvaluate(/library/book/author);//aforeach (XElement o in s){Console.WriteLine(o.Value);} 上面a处使用xpathevaluate()是获取值根据已知的xml知道获取到的是两个结点也就是返         回的是IEnumerableXElement类型若xpath表达式为/library/book[1]/author则指明是         返回一个结点的值即Author 1这显示默认的object是一个string类型那么后继的肯定         就应用string来处理。             实际中若的确无法确定时可以根据is来确定它的类型 var result xdoc.XPathEvaluate(/library/book/author);if (result is IEnumerableXElement elements){var author elements.FirstOrDefault()?.Value;Console.WriteLine(author);}else if (result is string str){Console.WriteLine(str);}else{Console.WriteLine(Unknown type);} xpathevaluate()也可以用于属性例如/library/book/id但要注意类型的转换与筛选。 XDocument xdoc XDocument.Load(book.xml);//不能直接IEnumerableXAttributeIEnumerableobject result (IEnumerableobject)xdoc.XPathEvaluate(/library/book/id);foreach (XAttribute attribute in result)//a{Console.WriteLine(attribute.Value);} XPathEvaluate若有多个结果需要枚举只能使用IEnumerableobject来接收结果。这         是因为XPath表达式可能匹配多种类型的节点例如元素、属性、注释等所以返回的结果         类型是多样的。虽然我们可以使用强制类型转换来尝试将结果转换为特定类型但这种方式         并不总是可行的因为我们无法预知XPath表达式最终会匹配到哪些类型的节点。             最后在a处枚举时再逐个隐式转换成对应结点。                               问/library/book/id与/library/book[id]有什么区别         答两者是两个不同的XPath表达式区别在于匹配的节点类型和结果。             /library/book/id                 这个XPath表达式匹配book元素下的id属性。它返回的是book元素的id属性的集合                 每个属性都是一个XAttribute对象。例如如果有两个book元素每个元素都有一                 个id属性那么这个表达式将返回两个XAttribute对象。             /library/book[id]                 这个XPath表达式匹配具有id属性的book元素。它返回的是具有id属性的book元素的                 集合每个元素都是一个XElement对象。例如如果有两个book元素其中一个具                 有id属性另一个没有id属性那么这个表达式将返回一个XElement对象。             /library/book/id返回的是id属性而/library/book[id]返回的是具有id属性的book         元素。这两个表达式的结果类型不同需要根据具体的需求选择使用哪个表达式。      三、对XML的增删查改 1、Xml增删查改登录                  思想每次变化都是保存xml然后重新加载xml保持xml一直更新。         图01                  2、以xmldocument操作          private void Form1_Load(object sender, EventArgs e){LoadToListView();}private void LoadToListView(){listView1.Items.Clear();XmlDocument xmldoc new XmlDocument();xmldoc.Load(UserData.xml);XmlNodeList ns xmldoc.SelectNodes(//user);foreach (XmlNode n in ns){ListViewItem item new ListViewItem(n.Attributes[id].InnerText);item.SubItems.Add(n.SelectSingleNode(name).InnerText);item.SubItems.Add(n.SelectSingleNode(password).InnerText);listView1.Items.Add(item);}button2.Enabled false;}private void button1_Click(object sender, EventArgs e)//增加{string id txtAddID.Text.Trim();if (id ) return;XmlDocument xmldoc new XmlDocument();xmldoc.Load(UserData.xml);XmlNodeList ns xmldoc.SelectNodes(/Users/user[id id ]);if (ns.Count 0){MessageBox.Show(已经有该ID);return;}XmlElement root xmldoc.DocumentElement;XmlElement user xmldoc.CreateElement(user);user.SetAttribute(id, id);XmlElement name xmldoc.CreateElement(name);name.InnerText txtAddUser.Text.Trim();XmlElement pwd xmldoc.CreateElement(password);pwd.InnerText txtAddPwd.Text.Trim();user.AppendChild(name);user.AppendChild(pwd);root.AppendChild(user);xmldoc.Save(UserData.xml);LoadToListView();txtAddID.Text ;txtAddUser.Text ;txtAddPwd.Text ;}private void button2_Click(object sender, EventArgs e)//修改{XmlDocument xmldoc new XmlDocument();xmldoc.Load(UserData.xml);string id txtEditID.Text.Trim();XmlNode n xmldoc.SelectSingleNode(/Users/user[id id ]);n.SelectSingleNode(name).InnerText txtEditUser.Text.Trim();n.SelectSingleNode(password).InnerText txtEditPwd.Text.Trim();xmldoc.Save(UserData.xml);LoadToListView();txtEditID.Text ;txtEditUser.Text ;txtEditPwd.Text ;}private void listView1_SelectedIndexChanged(object sender, EventArgs e){if (listView1.SelectedItems.Count 0) return;button2.Enabled true;ListViewItem lvitem listView1.SelectedItems[0];string id lvitem.Text;txtEditID.Text id;txtEditUser.Text lvitem.SubItems[1].Text;txtEditPwd.Text lvitem.SubItems[2].Text;}private void button4_Click(object sender, EventArgs e)//删除{if (listView1.SelectedItems.Count 0) return;string id listView1.SelectedItems[0].Text;XmlDocument xmldoc new XmlDocument();xmldoc.Load(UserData.xml);XmlNode n xmldoc.SelectSingleNode(/Users/user[id id ]);xmldoc.DocumentElement.RemoveChild(n);xmldoc.Save(UserData.xml);LoadToListView();txtEditID.Text ;txtEditUser.Text ;txtEditPwd.Text ;}private void button3_Click(object sender, EventArgs e)//登录{string use txtLogUser.Text.Trim();string pwd txtLogPwd.Text.Trim();XmlDocument xmldoc new XmlDocument();xmldoc.Load(UserData.xml);XmlNodeList ns xmldoc.SelectNodes(//name[. use ]);if (ns.Count 0){MessageBox.Show(用户名错误);return;}else{bool log false;foreach (XmlNode n in ns){if (n.NextSibling.InnerText pwd){MessageBox.Show(登录成功);log true;txtLogUser.Text ;txtLogPwd.Text ;break;}}if (!log){MessageBox.Show(密码错误);}}} 3、以xdocument进行操作      private void LoadToListView(){listView1.Items.Clear();XDocument xdoc XDocument.Load(UserData.xml);var eles xdoc.XPathSelectElements(//user);foreach (XElement ele in eles){ListViewItem item new ListViewItem(ele.Attribute(id).Value);item.SubItems.Add(ele.Element(name).Value);item.SubItems.Add(ele.Element(password).Value);listView1.Items.Add(item);}button2.Enabled false;}private void button1_Click(object sender, EventArgs e)//增加{string id txtAddID.Text.Trim();if (id ) return;XDocument xdoc XDocument.Load(UserData.xml);var eles xdoc.XPathSelectElements(/Users/user[id id ]);if (eles.Count() 0){MessageBox.Show(已经有该ID); return;}//XElement ele xdoc.Root.Elements(user).Single(x x.Attribute(id).Value id);//if (ele ! null)//{//    MessageBox.Show(已经有该ID); return;//}XElement user new XElement(user);user.SetAttributeValue(id, id);user.SetElementValue(name, txtAddUser.Text.Trim());user.SetElementValue(password, txtAddPwd.Text.Trim());xdoc.Root.Add(user);xdoc.Save(UserData.xml);LoadToListView();txtAddID.Text ;txtAddUser.Text ;txtAddPwd.Text ;}private void button2_Click(object sender, EventArgs e)//修改{XDocument xdoc XDocument.Load(UserData.xml);string id txtEditID.Text.Trim();XElement user xdoc.XPathSelectElement(/Users/user[id id ]);user.SetElementValue(name, txtEditUser.Text.Trim());user.SetElementValue(password, txtEditPwd.Text.Trim());xdoc.Save(UserData.xml);LoadToListView();txtEditID.Text ;txtEditUser.Text ;txtEditPwd.Text ;}private void listView1_SelectedIndexChanged(object sender, EventArgs e){if (listView1.SelectedItems.Count 0) return;button2.Enabled true;ListViewItem lvitem listView1.SelectedItems[0];string id lvitem.Text;txtEditID.Text id;txtEditUser.Text lvitem.SubItems[1].Text;txtEditPwd.Text lvitem.SubItems[2].Text;}private void button4_Click(object sender, EventArgs e)//删除{if (listView1.SelectedItems.Count 0) return;string id listView1.SelectedItems[0].Text;XDocument xdoc XDocument.Load(UserData.xml);XElement user xdoc.XPathSelectElement(/Users/user[id id ]);user.Remove();xdoc.Save(UserData.xml);LoadToListView();txtEditID.Text ;txtEditUser.Text ;txtEditPwd.Text ;}private void button3_Click(object sender, EventArgs e)//登录{string user txtLogUser.Text.Trim();string pwd txtLogPwd.Text.Trim();XDocument xdoc XDocument.Load(UserData.xml);var eles xdoc.XPathSelectElements(//name[. user ]);if (eles.Count() 0){MessageBox.Show(用户名错误);return;}else{bool log false;foreach (XElement ele in eles){var bros ele.ElementsAfterSelf(password);foreach (XElement bro in bros){if (bro.Value txtLogPwd.Text.Trim()){MessageBox.Show(登录成功!);log true;txtLogUser.Text ;txtLogPwd.Text ;break;//只能退出当前循环需要在外层循环中根据log再退出}}}if (!log){MessageBox.Show(密码错误);}}} 推荐使用xdocument一是本身比较简洁二是里面可以使用lambdar表达式                       问xdoc.Root.Elements(user)与xdoc.Elements(user)有什么区别         答区别在于它们选择元素的起始位置不同.elements()只会对直接子元素搜索不会对后         代所有元素搜索。             因此前面搜索的是根元素下面的子元素而后者搜索的是仅是根元素。              4、问本地名称LocalName和可选的命名空间Namespace有什么区别?         答在 XML 中每个元素和属性都有一个名称名称由本地名称和命名空间组成。             (1)本地名称LocalName             表示元素或属性的名称的本地部分即不包含命名空间前缀的部分。本地名称是元素或         属性在其所在命名空间中的唯一标识符。例如在 book元素中本地名称是 book。             (2)命名空间Namespace             用于标识和区分 XML 元素或属性的命名空间。命名空间提供了一种在不同 XML 文档之         间进行唯一标识的方式。它通常以 URIUniform Resource Identifier的形式表示。命         名空间可以与元素或属性的本地名称结合形成该元素或属性的完整名称。例如         在 ns:book元素中ns 是命名空间前缀表示该元素属于以 ns 前缀定义的命名空间。             在 XML 中命名空间的目的是避免元素和属性名称的冲突。它允许不同来源的 XML          数据在同一个文档中存在并区分开来。区别 rootbook xmlnshttp://example.com/bookstitleThe Adventures of Tom Sawyer/titleauthorMark Twain/author/bookns:book xmlns:nshttp://example.com/novelsns:titleThe Catcher in the Rye/ns:titlens:authorJ.D. Salinger/ns:author/ns:book/root 上面有两个 book元素但它们位于不同的命名空间中。在第一个 book元素中         内部元素的本地名称是title 和author并且默认命名空间为http://example.com/books。         而在第二个 ns:book元素中内部元素的本地名称是 title 和 author并且命名空间         为 http://example.com/novels。             通过这种方式两个 book元素及其内部元素虽然具有相同的本地名称但由于位于         不同的命名空间中可以被区分开来。因此本地名称和命名空间一起描述了 XML 元素或         属性的唯一标识符并在避免冲突的同时提供了更丰富的语义和上下文信息。                           问:xml使用命名空间的原因         答使用命名空间的主要目的之一是确保在处理来自不同来源如不同网站的 XML 数据         时能够将它们正确区分开来并避免名称冲突。             XML 是一种通用的数据交换格式用于在不同系统和平台之间传递数据。不同的组织、         应用程序或网站可能定义了具有相同名称的元素和属性但它们在语义上可能具有不同的         含义。             通过使用命名空间可以将相同的元素或属性名称与特定的命名空间关联起来从而         将其作为唯一标识符。这样在处理包含来自不同命名空间的 XML 数据的文档时可以确         保元素和属性的语义正确并且不会混淆。             例如假设有两个网站 A 和 B它们都使用了名称为 “book” 的元素来描述书籍的信         息。如果没有命名空间当将来自网站 A 和网站 B 的 XML 数据合并到同一个文档中时         就无法区分它们并且会出现名称冲突。             通过为网站 A 定义命名空间 http://www.example.com/siteA为网站 B 定义命名空         间 http://www.example.com/siteB每个网站的 book 元素就能够在合并的文档中保持         其唯一性和上下文。这样在处理合并文档时可以根据命名空间将元素正确区分为来自         网站 A 还是网站 B并根据其命名空间进行相应的处理。             因此使用命名空间可以确保在处理来自不同来源的 XML 数据时元素和属性能够正         确识别和解释并避免名称冲突和歧义。 四、隐式类型转换与显式类型转换 1、隐匿类型转换                      隐式类型转换是指在编译时自动将一种类型转换为另一种类型而无需显式地进行类型         转换操作。这种类型转换是安全的因为它只允许从一种类型到另一种类型的转换而不会         丢失数据或引发异常。隐式类型转换通常发生在以下情况下             (1)当将一个小范围的整数类型赋值给一个大范围的整数类型时如将int类型赋值给         long类型。             (2)当将一个派生类的实例赋值给一个基类类型时如将一个派生类的对象赋值给一         个基类的引用变量。             (3)当将一个浮点数类型赋值给一个更高精度的浮点数类型时如将float类型赋值给         double类型。 int num1 10;long num2 num1; // 隐式将int类型转换为long类型string str 123;int num3 Convert.ToInt32(str); // 显式将string类型转换为int类型float f 3.14f;double d f; // 隐式将float类型转换为double类型Animal animal new Dog(); 注意:隐式类型转换只能在类型之间存在继承关系或者存在内置的转换规则时才能进行。         如果类型之间没有直接的转换关系那么就需要使用显式类型转换来进行转换操作。               2、implicit隐式类型转换                      使用implicit关键字定义的隐式转换操作符允许在不进行显式转换的情况下将一个类         型隐式转换为另一个类型。这种转换是自动进行的不需要显式调用转换方法。 public class Distance{public double Meters { get; }public Distance(double meters){Meters meters;}public static implicit operator double(Distance distance){return distance.Meters;}}Distance distance new Distance(10.5);// 定义一个Distance类型的变量double meters distance;// 将Distance类型隐式转换为double类型Console.WriteLine(meters); // 输出: 10.5 上面定义了一个Distance类其中包含一个Meters属性和一个隐式转换操作符。该隐式         转换操作符允许将Distance类型隐式转换为double类型。             注意             (1)隐式转换操作符必须定义为公共静态方法并且返回目标类型的值。             (2)隐式转换操作符只能定义在类或结构体中。             (3)隐式转换操作符只能定义一个参数该参数是要转换的源类型。             (4)隐式转换操作符必须是从源类型到目标类型的转换不能反过来定义。             (5)隐式转换操作符应该是安全的不应该导致数据丢失或引发异常。              上面5个注意的原因             (1)因为隐式转换是一种自动进行的转换不需要显式调用转换方法。将隐式转换操作         符定义为公共静态方法可以确保在需要进行隐式转换时可以访问和调用该方法。同时让         右端类型与左端类型一致就必须返回目标类型。             (2)隐式转换是一种类型之间的转换关系需要在类型的定义中进行定义和实现。只有         类或结构体才能定义方法因此隐式转换操作符只能定义在类或结构体中。             (3)隐式转换是从源类型到目标类型的转换。在进行隐式转换时只需要提供源类型的         值就可以自动进行转换。因此隐式转换操作符只需要一个参数即要转换的源类型。             (4)隐式转换是一种自动进行的转换不需要显式调用转换方法。在进行隐式转换时         编译器会自动查找匹配的隐式转换操作符进行转换。如果允许反过来定义隐式转换操作符         可能会导致歧义和不确定性。             (5)为了确保转换的正确性和可靠性。隐式转换是一种自动进行的转换如果转换不是         安全的可能会导致数据丢失或引发异常。因此为了保证程序的正确性和可靠性隐式         转换操作符应该是安全的。如果需要进行不安全的转换应该使用显式转换操作符来明确         指定转换。               3、Explicit显式类型转换                      显式类型转换explicit主要应用的场景是防止不必要的隐式转换。在某些情况下         隐式转换可能会导致代码可读性降低或意外类型转换因此需要使用显式转换来明确表达         转换的意图。例如在类的构造函数中为了避免意外的隐式转换最好尽可能多地使用         显式转换。             explicit是一个关键字用于定义显式转换操作符。显式转换操作符允许程序员在不         同类型之间进行显式转换。             使用explicit关键字定义的显式转换操作符必须是公共静态方法并且必须返回目标         类型。它们通常被用于将一个较大的类型转换为一个较小的类型以避免数据丢失。 public class Distance{private double meters;public Distance(double meters){this.meters meters;}public static explicit operator int(Distance distance){return (int)distance.meters;}}class Program{static void Main(string[] args){Distance distance new Distance(1000);int meters (int)distance; // 使用显式转换操作符将Distance类型转换为int类型Console.WriteLine(meters); // 输出1000}} 上面Distance类定义了一个显式转换操作符将Distance类型转换为int类型。在         Main方法中我们创建了一个Distance对象并使用显式转换操作符将其转换为int类型         并将结果赋给meters变量。注意             (1)explicit关键字只能用于定义显式转换操作符而不能用于隐式转换操作符。             (2)显式转换操作符必须定义在类或结构体中。             (3)显式转换操作符必须是公共的静态方法。             (4)显式转换操作符必须返回目标类型。             (5)显式转换操作符通常用于将一个较大的类型转换为一个较小的类型以避免数据         丢失。因此在进行显式转换时需要注意可能会发生数据截断的情况。             下面是华氏温度与温度的自定义显式转换定义 public class Temperature{private double celsius;public Temperature(double celsius){this.celsius celsius;}public static explicit operator Fahrenheit(Temperature temperature){double fahrenheit (temperature.celsius * 9 / 5) 32;return new Fahrenheit(fahrenheit);}}public class Fahrenheit{private double temperature;public Fahrenheit(double temperature){this.temperature temperature;}public override string ToString(){return ${temperature}°F;}}class Program{static void Main(string[] args){Temperature temperature new Temperature(25);Fahrenheit fahrenheit (Fahrenheit)temperature; // 使用显式转换操作符将Temperature类型转换为Fahrenheit类型Console.WriteLine(fahrenheit); // 输出77°F}} 注意             (1)在显式转换操作符中我们可以根据需要执行任意的转换逻辑。             (2)显式转换操作符可以在任意两个自定义类型之间进行定义只要转换逻辑是可行的。             (3)在进行显式转换时需要确保目标类型能够接受转换后的值否则可能会引发异常         或产生不可预期的结果。             (4)显式转换操作符可以用于自定义类型的转换以便在不同的类型之间进行数据转换         和操作。               4、Operator运算符重载                      可以通过运算符重载来重定义已经存在的运算符的行为。这意味着我们可以为自定义类         型定义与标准运算符如算术运算符、关系运算符等相关的操作。             例如我们可以重载加法运算符以实现自定义类型的相加操作或者重载相等运         算符以实现自定义类型的相等性比较。             运算符重载的目的是为了提供一种直观和自然的方式来操作自定义类型对象使其行为         与内置类型对象类似。这样我们可以使用操作符来操作自定义类型使代码更具可读性和         简洁性。             注意在进行运算符重载时我们只能重载已经存在的运算符无法创建新的运算符。         这是由C#语言规范所决定的。可以通过运算符重载来自定义行为的常见运算符             一元运算符, -, !, , –             算术运算符, -, *, /, %, , –             关系运算符, !, , , ,             逻辑运算符, ||, !             位运算符, |, ^, ~, ,             索引器[]             通过定义相应的重载方法我们可以修改这些运算符在自定义类型上的操作行为。             注意下面写法:public static 返回类型 operator 符号(参数         (1)算术运算符重载             我们可以重载算术运算符如加法运算符、减法运算符-、乘法运算符*         和除法运算符/。例如假设我们有一个自定义的Vector类我们可以重载加法运算         符来执行向量的加法操作。 private static void Main(){Vector v1 new Vector() { X 1, Y 2 };Vector v2 new Vector() { X 4, Y 3 };Vector v3 v1 v2;Console.WriteLine(v3.X);Console.ReadKey();}public class Vector{public int X { get; set; }public int Y { get; set; }public static Vector operator (Vector v1, Vector v2){return new Vector() { X v1.X v2.X, Y v1.Y v2.Y };}} (2)比较运算符重载             我们可以重载比较运算符如相等运算符、不等运算符!、大于运算符         和小于运算符。例如假设我们有一个自定义的Person类我们可以重载相         等运算符以比较两个人的年龄是否相等。 private static void Main(){Person p1 new Person() { Name Tom, Age 18 };Person p2 new Person() { Name John, Age 18 };Console.WriteLine(p1 p2);Console.WriteLine(p1.Equals(p2));Console.ReadKey();}public class Person{public string Name { get; set; }public int Age { get; set; }public static bool operator (Person p1, Person p2){return p1.Age p2.Age;}public static bool operator !(Person p1, Person p2){return p1.Age ! p2.Age;}} 问题一              重载后必须同时重载!。         问题二             重载后equals仍然是按原来进行引用相等性比较即比较两个对象是否指向相同         的内存地址而不是基于你重载的运算符进行的值相等性比较。             如果你希望Object.Equals(Person p1, Person p2)按照你重载的运算符来进行相等         性比较你可以通过重写Object.Equals(object o)方法来实现。事实上当前面的重载         写上时vs2022就会提醒             “重载与!后提示Person定义运算符或!,但不重写object.equals(object o)”             也就是说equals的结果可能与定义的结果不一样。若更改为一样则在类内重写 public override bool Equals(object o){if(o null || GetType()o.GetType()) return false;Person obj(Person)o;return Name obj.Name Ageobj.Age;} operator重载时应该注意             运算符重载的参数数量和类型是根据相应的运算符来确定的。例如对于二元运算符         如加法运算符重载方法的参数包括两个操作数而对于一元运算符如递增运算         符重载方法的参数只包括一个操作数。             运算符重载方法必须被声明为公共public和静态static。这是因为运算符重         载方法与类型本身而不是特定的实例相关联所以它们必须是静态的。同时为了允许外         部代码直接使用运算符重载方法也必须声明为公共的。             在使用运算符重载时需要注意以下几点             (1)编写清晰和可读性强的代码运算符重载是为了让代码更易读和理解所以应该         遵循良好的命名习惯并确保代码对其他开发人员易于理解。             (2)保持一致性运算符重载的行为应与内置运算符的行为保持一致。例如在重载         加法运算符时,它应该执行通常意义上的加法操作而不是执行其他奇怪或不相关的操作。             (3)谨慎地选择重载运算符应该谨慎选择需要重载的运算符以避免引起混淆或意         外的行为。不应该过度使用运算符重载只在有必要的情况下使用。             (4)重载运算符的对称性运算符重载应该具有对称性。例如如果重载了相等运算         符则还应该同时重载不等运算符!并且它们的行为应该是对称的。             (5)考虑运算符的预期用途在重载运算符时应该考虑到它们的预期用法和语义。         这样,其他人员在使用重载的运算符时可以有一个直观的期望,并且代码会更具可读性。 五、序列化 1、XML序列化              下面对一个ListPerson进行序列化。 private static void Main(){ListPerson list new ListPerson(){new Person(){NameTom,Age18},new Person(){NameJohn,Age19},new Person(){NameJack,Age20}};XmlSerializer ser new XmlSerializer(typeof(ListPerson));//typeof(Person)将报错using (FileStream fs File.OpenWrite(D:\22.xml)){ser.Serialize(fs, list);}Console.WriteLine(File.ReadAllText(D:\22.xml));Console.ReadKey();}public class Person{public int Age { get; set; }public string Name { get; set; }} 如果不需要写到文件中则只需要用内存流即可 internal class Program//a{private static void Main(){ListPerson list new ListPerson(){new Person(){NameTom,Age18},new Person(){NameJohn,Age19},new Person(){NameJack,Age20}};using (MemoryStream ms new MemoryStream()){XmlSerializer xml new XmlSerializer(typeof(ListPerson));xml.Serialize(ms, list);ms.Position 0;//b关键否则游标在末尾无法读出内容.每次读完游标在末尾。string s new StreamReader(ms).ReadToEnd();//XDocument xdoc XDocument.Load(ms);//string s xdoc.ToString(); //c不会包括声明部分需要手动添加//若用xmldocument就是全部,但由于是outerxml不会是标准的格式显示//XmlDocument xmldoc new XmlDocument();//xmldoc.Load(ms);//s xmldoc.OuterXml;//dConsole.WriteLine(s); // 输出序列化后的字符串}Console.ReadKey();}}public class Person{public int Age { get; set; }public string Name { get; set; }} 用using可以自行释放msusing块内定义的超出块外GC会自动回收。         ms也可以不用管GC也可以自动回收。也可以手动设置             ms.SetLength(0);//设置内存流长度为0也即变相释放了。             或者直接创建新的对象来清空内存流             msnew MemoryStream();             总之MemoryStream 会自动管理内存的释放但在特定情况下手动管理内存流可以         帮助避免潜在的内存问题。                      另外             xml需要公共方法person类必须public它的外界也必须是public。例如把person纳         入Program时Program也必须为public(a处)。             每一次内存流读后游标在末尾若想再次读取须置开头(b处)             xdoc与xmldoc取得xml内容有差异。xdoc取的是除声明外的xml。xmldoc虽然取得的是全         部xml但再没有回车table等格式方便眼睛识别格式。               2、问为什么xml序列化时不用加[serializable]而二进制序列必须加         答对于二进制序列化需要使用[serializable]特性标记类以便将类的定义信息如         字段、属性等包含在序列化流中。如果不标记为[serializable]则无法进行二进制序         列化。这是因为二进制序列化需要将类的定义信息作为序列化的开端然后按照对象的实         际状态进行序列化。             而对于XML序列化不需要显式地标记类为[serializable]。这是因为XML序列化使用         的是公共语言规范Common Language SpecificationCLS该规范要求所有公共类都         必须是可序列化的。因此在默认情况下所有公共类都可以进行XML序列化。             注意即使不需要显式地标记类为[serializable]但如果类中包含非公共字段或属         性则仍然无法进行XML序列化。因为这些字段或属性无法被序列化过程访问。             在C#中只有公共实例字段、公共静态字段、公共可读属性、公共只读属性、公共可         访问的事件和公共可访问的方法才能被序列化。私有成员不在此范围内因此无法直接进         行序列化。             然而有一种方法可以实现私有成员的序列化即使用反射Reflection。通过反         射我们可以访问私有成员并读取其值然后将其序列化。但是这种方法需要额外的代         码实现并且可能会影响性能。               3、下面写写自定义xml序列                  提示             XML序列化只会将对象的公有字段和属性序列化为XML而忽略对象的方法、事件和索         引器等。这是因为XML序列化的目的是保存对象的状态而方法、事件和索引器等通常表示         对象的行为和功能不是对象的状态的一部分。如果您希望将方法、事件和索引器等内容         一起序列化可以考虑使用其他序列化方法如Binary序列化或Json序列化。 internal class Program{private static void Main(){ListPerson list new ListPerson(){new Person() { Name Tom, Age 18 },new Person() { Name John, Age 19 },new Person() { Name Jack, Age 20 }};MySerializer(list, typeof(ListPerson));//Person p new Person() { Name Tom, Age 18 };//MySerializer(p, typeof(Person));Console.ReadKey();}private static void MySerializer(object obj, Type type){//主要针对ListT及Object情况if (obj is ICollection)//是否为集合{//ListT情况ICollection c (ICollection)obj;XDocument xdoc new XDocument();XElement xRoot new XElement(List);xdoc.Add(xRoot);foreach (var o in c){XElement item new XElement(item);PropertyInfo[] ps o.GetType().GetProperties();//先属性foreach (PropertyInfo p in ps){item.SetElementValue(p.Name, p.GetValue(o, null));}FieldInfo[] fs o.GetType().GetFields(); //后字段foreach (FieldInfo f in fs){item.SetElementValue(f.Name, f.GetValue(o));}xRoot.Add(item);}xdoc.Save(E:\22.xml);}else{//Object情况XDocument xdoc new XDocument();XElement xRoot new XElement(type.Name);xdoc.Add(xRoot);PropertyInfo[] ps type.GetProperties(); //先属性foreach (PropertyInfo p in ps){xRoot.SetElementValue(p.Name, p.GetValue(obj, null));//a}FieldInfo[] fs type.GetFields();//后字段foreach (FieldInfo f in fs){xRoot.SetElementValue(f.Name, f.GetValue(obj));}xdoc.Save(E:\22.xml);}}}public class Person{private string id;public string school xz;public int Age { get; set; }public string Name { get; set; }public void SayHi(string s){id 001;Console.WriteLine(s);}} 上面主要针对listT与person情况写有字段有属性下面看一下特征简化为只属性。                           问上面a处p.GetValue(obj, null)表示什么意思         答p和类是一个级别是概念级。如同佛家说的灵魂层面类与属性就是灵魂层面而         它们的实际对象或变量的值就是肉身。灵魂永久不变但可以轮回变化肉身(实例或值         因此p是属性是概念GetValue是取值obj是实例这样才灵魂与肉身相合取得         具体的值第二个参数是索引值因此有些属性是索引器是一组值不只一个值需要         指定索引。如果不是索引器就直接用null代表即可。               4、Attribute特性                  简言之特性实质就是一个标记方便后续任务的识别和处理。                      特性Attribute是一种用于在代码中添加元数据的机制。它们提供了一种在编译时         为代码添加附加信息的方式以便在运行时可以通过反射机制来获取这些信息。             特性的主要用途是为代码提供额外的元数据以便在运行时可以根据这些元数据执行         不同的操作。它们可以用于以下场景             代码注释和文档特性可以用于为代码添加注释、文档和说明。例如可以使用特性         来标记某个方法的用途、参数的含义等。             运行时行为修改特性可以用于在运行时修改代码的行为。通过读取特性中的元数据         可以根据不同的条件执行不同的逻辑。             自定义属性特性可以用于为类、方法、属性等添加自定义属性。这些属性可以用于         标记特定的行为或功能以便在运行时进行处理。             特性提供了一种灵活的方式来为代码添加额外的元数据并且可以通过反射机制在运         行时获取和处理这些元数据。                      特性在C#中可以看作是一种标记用于为代码添加附加的元数据信息。这些特性可以         在编译时被读取和处理以实现不同的功能或行为。             特性可以用于标记类、方法、属性、字段等代码元素并且可以为它们提供额外的信         息。在运行时可以使用反射机制来读取代码中的特性并根据特性中的元数据执行相应         的逻辑。                           问[XmlIgnore]是什么意思         答[XmlIgnore] 是一个属性应用程序用于指示在序列化和反序列化过程中忽略特定的         字段或属性。             当一个类被序列化成XML时所有公共的字段和属性都将被默认包括在XML中。然而         有时候我们可能希望某些字段或属性在序列化过程中被忽略掉以避免将不必要的数据暴         露给外部。这时我们可以在需要忽略的字段或属性上使用[XmlIgnore]属性。例如 public class Person{public string Name { get; set; }[XmlIgnore]public int Age { get; set; }} Age属性被标记为[XmlIgnore]因此在序列化Person对象时Age将被忽略掉。             注意[XmlIgnore]属性只能应用于公共的字段和属性。私有的字段或属性将不受影         响仍然会被序列化。另外[XmlIgnore]属性还可以应用于基类中的字段或属性以便         在派生类中忽略它们。               5、针对上面进行为人忽略的标记特性的设置和使用          internal class Program{private static void Main(){Person p new Person() { Name Tom, Age 18 };MySerializer(p, typeof(Person));Console.ReadKey();}private static void MySerializer(object obj, Type type){//主要针对ListT及Object情况if (obj is ICollection)//是否为集合{//ListT情况}else{//Object情况XDocument xdoc new XDocument();XElement xRoot new XElement(type.Name);xdoc.Add(xRoot);PropertyInfo[] ps type.GetProperties(); //先属性foreach (PropertyInfo p in ps){object[] objs p.GetCustomAttributes(typeof(MyIgnoreAttribute), false);//aif (objs.Length 0)//b 指定的特性若没有不用忽略{xRoot.SetElementValue(p.Name, p.GetValue(obj, null));}else//c 忽略{continue;}}xdoc.Save(E:\22.xml);}}}public class Person{[MyIgnore]//epublic int Age { get; set; }public string Name { get; set; }}public class MyIgnoreAttribute : Attribute//d{} a处获取自定义特性集合第一参数指定自定义特性的类型第二参数指定是否来自父类             继承。实际返回的应该是MyIgnoreAttribute类型为了简化用了var同时也不必进行             强制转换类型。         b处集体是否有值0有值说明该属性有这个特性就跳过继续c处否则必须处理。         d处因为特性就是一个标志无须更多的说明所以内部一般空代码。         e处特性可以直接忽略后面的Attribute字样而正常使用但为了简化一般在d处定义时             后缀就不要再加Attribute了。          六、浅拷贝与深拷贝 1、什么是浅拷贝什么是深拷贝                      浅拷贝和深拷贝是对象复制的两种不同方式。             浅拷贝是指创建一个新对象并将原对象的成员值复制到新对象中。如果对象包含引用         类型的成员那么浅拷贝只会复制引用而不会复制引用对象本身。这意味着新对象和原对         象的引用类型成员将指向同一个对象。修改其中一个对象的引用类型成员会影响到另一个         对象的相应成员。             浅拷贝通常使用MemberwiseClone方法或对象的复制构造函数来实现。             深拷贝是指创建一个新对象并将原对象的成员值复制到新对象中包括引用类型的成         员。这样新对象和原对象的引用类型成员都会指向各自独立的对象。修改其中一个对象的         引用类型成员不会影响到另一个对象的相应成员。深拷贝通常通过手动复制对象的成员         或者使用序列化和反序列化来实现。             区别和用途             浅拷贝适用于对象的成员都是值类型或不可变类型并且没有引用类型成员的情况。它         可以快速创建对象的副本但是修改其中一个对象的引用成员会影响到另一个对象。             深拷贝适用于对象包含引用类型成员的情况。它可以创建一个独立的对象副本修改其         中一个对象的成员不会影响到另一个对象。             实现深拷贝时可以使用以下方法             (1)使用自定义的拷贝构造函数或拷贝方法手动复制对象的成员包括引用类型的成         员。             (2)使用序列化和反序列化将对象序列化为字节流然后反序列化为一个新的对象。         这样可以实现对象的完全复制包括引用类型的成员。             在实现深拷贝时需要注意             对象及其所有引用类型成员都必须实现深拷贝以确保每个对象都有自己的独立副本。             如果对象的引用类型成员是可变类型如集合则需要确保在深拷贝过程中也复制         了这些成员的元素以避免共享相同的元素。             对象及其引用类型成员的成员也可能需要实现深拷贝以确保整个对象图都被正确复制。 internal class Program{private static void Main(){Person p1 new Person() { Name Tom, Age 18, Bike new Bike() { Brand 永久 } };Person p2 p1;//p2指向了p1并没发生拷贝//下面是浅拷贝Person p3 new Person();p3.Name p1.Name;p3.Age p1.Age;p3.Bike p1.Bike;//关键区别在于是否指向同一对象//下面是深拷贝Person p4 new Person();p4.Name p1.Name;p4.Age p1.Age;p4.Bike new Bike() { Brand p1.Bike.Brand };Console.ReadKey();}}public class Person{public string Name { get; set; }public int Age { get; set; }public Bike Bike { get; set; }} 2、实现浅拷贝与深拷贝                  (1)浅拷贝使用MemberwiseClone()返回类型是object注意类型转换。         (2)深拷贝使用二进制序列化和反序列化。                     或者先浅拷贝再手动对引用进行重新赋值。          internal class Program{private static void Main(){Person p1 new Person() { Name Tom, Age 18, Bike new Bike() { Brand 永久 } };Person p2 p1.QianCopy();p1.Name John;Console.WriteLine(p2.Name);Console.ReadKey();}}[Serializable]public class Person{public string Name { get; set; }public int Age { get; set; }public Bike Bike { get; set; }public Person QianCopy(){return this.MemberwiseClone() as Person;}public Person DeepCopy(){BinaryFormatter bf new BinaryFormatter();using (MemoryStream ms new MemoryStream()){bf.Serialize(ms, this);ms.Position 0; //areturn bf.Deserialize(ms) as Person;//b}}}[Serializable]public class Bike{public string Brand { get; set; }} 上面a处因为写入ms后游标在末尾需要重置到开头。         b处因为反序列化返回的是object需要强制转换。                           问string也是引用类型为什么在浅拷贝时无需关心它         答string在C#中被特殊对待具有不可变性。这意味着一旦创建了一个string对象它         的值就不能被修改。任何对string对象的修改实际上都会创建一个新的string对象。             当我们对一个string对象进行修改时实际上是创建了一个新的string对象而不是         修改原始的string对象。由于string是不可变的它的值在创建后就不能被修改。             所以在浅拷贝中当我们复制一个对象的string属性时实际上是复制了一个指向         原始string对象的引用。但当我们修改其中一个对象的string属性时实际上是创建了一         个新的string对象并将新的string对象赋值给属性而不会修改原始的string对象。因         此另一个对象的string属性不会受到影响。             因此这个规律暗合值类型的变化规律所以在浅拷贝中把它当作值类型。
http://www.dnsts.com.cn/news/120237.html

相关文章:

  • 中国城乡住建部建设部网站余姚专业网站建设公司
  • 校园网站建设目的如何做网络营销宣传
  • 上海省住房与城乡建设厅网站wordpress作品集插件
  • 广州网络推广公司有哪些网站自己怎么做优化
  • 网站备案流程2016公司要做网站
  • 响应式网站怎么设置网络科技公司税收优惠政策
  • 免费软件下载网站入口正能量网站建设 作用
  • 网站设计遵循的原则凡科商城小程序收费吗
  • 网站建设价类型友汇网站建设一般多少钱
  • 电子商务网站开发背景及意义网络测速器
  • 传媒网站集团定制网站建设公司
  • 网站运营推广方案用于做网站的软件
  • vue做的网站有什么天津做网站制作
  • 微商网站北京pk10做号网站
  • 如何在后台做网站流程网站名称填写什么
  • 网站论坛制作搜索公司信息的网站
  • 专业做写生的网站营销网站怎么做
  • 东莞微网站制作公司全国各大网站
  • c 用mysql做的网站网站建设佰金手指科杰三
  • 深圳网站建设费用多少网站建设宣传文案
  • 门户网站免费建站上饶市建设局有什么网站
  • 福州网站备案营销型网站建设项目需求表
  • 做网站需要学php吗深圳网站的网络公司
  • dw做网站图片运用广西旅游必去十大景点排名
  • 做网站前怎么写文档十大永久免费污染软件
  • 公司网站建设需求表福建外贸网站
  • 张家界网站建设多少钱重庆手机网站开发
  • 中文电商网站模板有网站源码 怎么建设网站
  • 做网站需要会什么网站建设的售后服务流程
  • 正规漫画网站开发流程做的网站百度找不到了