(14)嵌套列表,Xpath路徑表達式,XML增刪查改,Implicit,Operator,Xml序列化,淺拷貝與深拷貝


一、作業問題


?? ?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)多維數組

?? ??? ??? ?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] 的方式。在添加或刪除元素時,需要小心對嵌套列
?? ??? ?表的索引進行管理,以避免出現越界或邏輯錯誤。

?? ??? ??? ?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>>
?? ??? ??? ?這是一個將鍵值對中的值作為列表的字典。它適用于需要按鍵進行分組的場景。
?? ??? ??? ?使用場景:當需要對數據進行分組,并且每個組可以包含多個元素時,可以使用這樣的
?? ??? ?嵌套字典。
?? ??? ??? ?注意:當添加新的元素時,需要先檢查字典中是否存在對應的鍵,如果不存在則創建一
?? ??? ?個新的列表,并將元素加入到列表中。當訪問嵌套字典中的元素時,先訪問鍵的值(即列
?? ??? ?表),然后再通過索引訪問列表中的元素。

?? ??? ??? ?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>>
?? ??? ??? ?這是一個嵌套的哈希集合,用于存儲唯一的元素集合。
?? ??? ??? ?使用場景:當需要存儲多個唯一的集合,并且每個集合可能包含多個唯一元素時,可以
?? ??? ?使用嵌套的哈希集合。
?? ??? ??? ?注意:當添加新的元素時,需要先檢查嵌套的哈希集合中是否存在對應的集合,如果不
?? ??? ?存在則創建一個新的集合,并將元素加入到集合中。當訪問嵌套哈希集合中的元素時,先訪
?? ??? ?問外層集合,然后再通過迭代方式訪問內層集合中的元素。

?? ??? ??? ?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 };//aset.Add(set0);set.Add(set1);set.Add(set2);Console.WriteLine(set.ElementAt(2).ElementAt(1));//7HashSet<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()函數返回字符串的字符數,你應該用&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[@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 version="1.0" encoding="utf-8" ?><school><student id="001" position="1"><name>許萬里</name><age>18</age></student><student id="002" position="2"><name>劉萬仁</name><age>19</age></student><student id="003" position="1"><name>晨微</name><age>20</age></student><student id="004" position="1"><name>郎吉祥</name><age>21</age></student></school>


?? ??? ?利用xmldocument使用xpath:

?? ??? ?XmlDocument xmldoc = new XmlDocument();xmldoc.Load("student.xml");XmlNodeList xmlns = xmldoc.SelectNodes("//student[@id][@position='1']");foreach (XmlNode n in xmlns){Console.WriteLine($"{n.Name},{n.Attributes["id"].Value}");}


?? ??? ?
?? ??? ?
?? ?3、XDocumetn中使用xpath的有哪些?
?? ??? ?
?? ??? ??? ?XDocument類提供了三個主要的方法來使用XPath表達式進行元素選擇和查詢:
?? ??? ?XPathSelectElement方法:
?? ??? ??? ?使用XPath表達式選擇單個元素。它返回滿足XPath條件的第一個元素,如果沒有匹配的
?? ??? ??? ?元素,則返回null。
?? ??? ?XPathSelectElements方法:
?? ??? ??? ?使用XPath表達式選擇多個元素。它返回一個IEnumerable<XElement>對象,其中包含滿
?? ??? ??? ?足XPath條件的所有元素。
?? ??? ?XPathEvaluate方法:
?? ??? ??? ?使用XPath表達式對文檔進行求值。它返回一個object類型的結果,根據XPath表達式的
?? ??? ??? ?求值結果的類型可能會有所不同。
?? ??? ??? ?
?? ??? ??? ?這些方法允許您在XDocument中使用XPath表達式來選擇元素或執行XPath查詢。請注意,
?? ??? ?在使用這些方法之前,需要導入System.Xml.Linq和System.Xml.XPath命名空間。linq可以
?? ??? ?進一步提供謂詞、篩選、修改XML文檔等功能。?
?? ??? ?例xml文件:

?? ??? ?<library><book><title>Book 1</title><author>Author 1</author></book><book><title>Book 2</title><author>Author 2</author></book></library>


?? ??? ?
?? ??? ?使用xpath操作

?? ??? ?XDocument xdoc = XDocument.Load("book.xml");IEnumerable<XElement> 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);IEnumerable<object> s = (IEnumerable<object>)xdoc.XPathEvaluate("/library/book/author");//aforeach (XElement o in s){Console.WriteLine(o.Value);}


?? ??? ?上面a處使用xpathevaluate()是獲取值,根據已知的xml知道獲取到的是兩個結點,也就是返
?? ??? ?回的是IEnumerable<XElement>類型,若xpath表達式為/library/book[1]/author,則指明是
?? ??? ?返回一個結點的值,即"Author 1",這顯示默認的object是一個string類型,那么后繼的肯定
?? ??? ?就應用string來處理。
?? ??? ??? ?實際中若的確無法確定時,可以根據is來確定它的類型:

?? ??? ?var result = xdoc.XPathEvaluate("/library/book/author");if (result is IEnumerable<XElement> 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");//不能直接IEnumerable<XAttribute>IEnumerable<object> result = (IEnumerable<object>)xdoc.XPathEvaluate("/library/book/@id");foreach (XAttribute attribute in result)//a{Console.WriteLine(attribute.Value);}


?? ??? ??? ?XPathEvaluate若有多個結果需要枚舉,只能使用IEnumerable<object>來接收結果。這
?? ??? ?是因為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 文檔之
?? ??? ?間進行唯一標識的方式。它通常以 URI(Uniform Resource Identifier)的形式表示。命
?? ??? ?名空間可以與元素或屬性的本地名稱結合,形成該元素或屬性的完整名稱。例如,
?? ??? ?在 <ns:book>元素中,ns 是命名空間前綴,表示該元素屬于以 ns 前綴定義的命名空間。
?? ??? ??? ?在 XML 中,命名空間的目的是避免元素和屬性名稱的沖突。它允許不同來源的 XML?
?? ??? ?數據在同一個文檔中存在并區分開來。區別:

?? ??? ??? ?<root><book xmlns="http://example.com/books"><title>The Adventures of Tom Sawyer</title><author>Mark Twain</author></book><ns:book xmlns:ns="http://example.com/novels"><ns:title>The Catcher in the Rye</ns:title><ns:author>J.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 && Age==obj.Age;}


?? ?
?? ??? ?operator重載時應該注意:
?? ??? ??? ?運算符重載的參數數量和類型是根據相應的運算符來確定的。例如,對于二元運算符
?? ??? ?(如加法運算符),重載方法的參數包括兩個操作數,而對于一元運算符(如遞增運算
?? ??? ?符),重載方法的參數只包括一個操作數。
?? ??? ??? ?運算符重載方法必須被聲明為公共(public)和靜態(static)。這是因為運算符重
?? ??? ?載方法與類型本身而不是特定的實例相關聯,所以它們必須是靜態的。同時,為了允許外
?? ??? ?部代碼直接使用運算符,重載方法也必須聲明為公共的。
?? ??? ??? ?在使用運算符重載時,需要注意以下幾點:
?? ??? ??? ?(1)編寫清晰和可讀性強的代碼:運算符重載是為了讓代碼更易讀和理解,所以應該
?? ??? ?遵循良好的命名習慣,并確保代碼對其他開發人員易于理解。
?? ??? ??? ?(2)保持一致性:運算符重載的行為應與內置運算符的行為保持一致。例如,在重載
?? ??? ?加法運算符時,它應該執行通常意義上的加法操作,而不是執行其他奇怪或不相關的操作。
?? ??? ??? ?(3)謹慎地選擇重載運算符:應該謹慎選擇需要重載的運算符,以避免引起混淆或意
?? ??? ?外的行為。不應該過度使用運算符重載,只在有必要的情況下使用。
?? ??? ??? ?(4)重載運算符的對稱性:運算符重載應該具有對稱性。例如,如果重載了相等運算
?? ??? ?符(==),則還應該同時重載不等運算符(!=),并且它們的行為應該是對稱的。
?? ??? ??? ?(5)考慮運算符的預期用途:在重載運算符時,應該考慮到它們的預期用法和語義。
?? ??? ?這樣,其他人員在使用重載的運算符時可以有一個直觀的期望,并且代碼會更具可讀性。


五、序列化


?? ?1、XML序列化
?? ?
?? ??? ?下面對一個List<Person>進行序列化。

?? ??? ?private static void Main(){List<Person> list = new List<Person>(){new Person(){Name="Tom",Age=18},new Person(){Name="John",Age=19},new Person(){Name="Jack",Age=20}};XmlSerializer ser = new XmlSerializer(typeof(List<Person>));//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(){List<Person> list = new List<Person>(){new Person(){Name="Tom",Age=18},new Person(){Name="John",Age=19},new Person(){Name="Jack",Age=20}};using (MemoryStream ms = new MemoryStream()){XmlSerializer xml = new XmlSerializer(typeof(List<Person>));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可以自行釋放ms,using塊內定義的超出塊外,GC會自動回收。
?? ??? ?ms也可以不用管,GC也可以自動回收。也可以手動設置:
?? ??? ??? ?ms.SetLength(0);//設置內存流長度為0,也即變相釋放了。
?? ??? ??? ?或者,直接創建新的對象來清空內存流:
?? ??? ??? ?ms=new 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 Specification,CLS),該規范要求所有公共類都
?? ??? ?必須是可序列化的。因此,在默認情況下,所有公共類都可以進行XML序列化。
?? ??? ??? ?注意,即使不需要顯式地標記類為[serializable],但如果類中包含非公共字段或屬
?? ??? ?性,則仍然無法進行XML序列化。因為這些字段或屬性無法被序列化過程訪問。
?? ??? ??? ?在C#中,只有公共實例字段、公共靜態字段、公共可讀屬性、公共只讀屬性、公共可
?? ??? ?訪問的事件和公共可訪問的方法才能被序列化。私有成員不在此范圍內,因此無法直接進
?? ??? ?行序列化。
?? ??? ??? ?然而,有一種方法可以實現私有成員的序列化,即使用反射(Reflection)。通過反
?? ??? ?射,我們可以訪問私有成員并讀取其值,然后將其序列化。但是,這種方法需要額外的代
?? ??? ?碼實現,并且可能會影響性能。
?? ?
?? ?
?? ?3、下面寫寫自定義xml序列
?? ??? ?
?? ??? ?提示:
?? ??? ??? ?XML序列化只會將對象的公有字段和屬性序列化為XML,而忽略對象的方法、事件和索
?? ??? ?引器等。這是因為XML序列化的目的是保存對象的狀態,而方法、事件和索引器等通常表示
?? ??? ?對象的行為和功能,不是對象的狀態的一部分。如果您希望將方法、事件和索引器等內容
?? ??? ?一起序列化,可以考慮使用其他序列化方法,如Binary序列化或Json序列化。

?? ??? ?internal class Program{private static void Main(){List<Person> list = new List<Person>(){new Person() { Name = "Tom", Age = 18 },new Person() { Name = "John", Age = 19 },new Person() { Name = "Jack", Age = 20 }};MySerializer(list, typeof(List<Person>));//Person p = new Person() { Name = "Tom", Age = 18 };//MySerializer(p, typeof(Person));Console.ReadKey();}private static void MySerializer(object obj, Type type){//主要針對List<T>及Object情況if (obj is ICollection)//是否為集合{//List<T>情況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);}}


?? ??? ?上面主要針對list<T>與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){//主要針對List<T>及Object情況if (obj is ICollection)//是否為集合{//List<T>情況}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.pswp.cn/news/36829.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/36829.shtml
英文地址,請注明出處:http://en.pswp.cn/news/36829.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

在單元測試中使用Jest模擬VS Code extension API

對VS Code extension進行單元測試時通常會遇到一個問題&#xff0c;代碼中所使用的VS Code編輯器的功能都依賴于vscode庫&#xff0c;但是我們在單元測試中并沒有添加對vscode庫的依賴&#xff0c;所以導致運行單元測試時出錯。由于vscode庫是作為第三方依賴被引入到我們的VS C…

[oneAPI] BERT

[oneAPI] BERT BERT訓練過程Masked Language Model&#xff08;MLM&#xff09;Next Sentence Prediction&#xff08;NSP&#xff09;微調 總結基于oneAPI代碼 比賽&#xff1a;https://marketing.csdn.net/p/f3e44fbfe46c465f4d9d6c23e38e0517 Intel DevCloud for oneAPI&…

JVM 中的編譯器

在Java的世界里,JVM(Java Virtual Machine)扮演了重要的角色。JVM是一個虛擬機,是Java程序的運行環境,它能夠將Java字節碼文件解釋執行,使得Java程序可以跨平臺。在JVM內部,有一個重要的組件就是編譯器,它的作用就是將Java源代碼編譯成字節碼,讓JVM可以識別并執行。 …

redis集群和分片-Redis Cluster:分布式環境中的數據分片、主從復制和 Sentinel 哨兵

當涉及到 Redis 中的集群、分片、主從復制和 Sentinel 哨兵時&#xff0c;這些是構建分布式 Redis 環境中非常重要的概念和組件。下面詳細介紹這些概念以及它們在分布式環境中的作用。 Redis Cluster Redis Cluster 是 Redis 官方提供的分布式解決方案&#xff0c;用于管理和…

React源碼解析18(4)------ completeWork的工作流程【mount】

摘要 經過上一章&#xff0c;我們得到的FilberNode已經具有了child和return屬性。一顆Filber樹的結構已經展現出來了。 那我們最終是想在頁面渲染真實的DOM。所以我們現在要在completeWork里&#xff0c;構建出一顆離屏的DOM樹。 之前在說FilberNode的屬性時&#xff0c;我們…

zabbix案例--zabbix監控Tomcat

目錄 一、 部署tomcat 二、配置zabbix-java-gateway 三、配置zabbix-server 四、配置zabbix-web界面 一、 部署tomcat tar xf apache-tomcat-8.5.16.tar.gz -C /usr/local/ ln -sv /usr/local/apache-tomcat-8.5.16/ /usr/local/tomcat cd /usr/local/tomcat/bin開啟JMX…

Vscode 常用操作教程

一、語言換成中文 這是我們可以直接點擊左邊欄第四個圖標搜索插件 chinese ,也可以直接ctrlshiftp快捷鍵也會出來如圖所示圖標&#xff0c;出來chinese 插件之后選擇安裝install,安裝完成之后重新ctrlshiftp會出現如圖所示頁面 找到我的鼠標在的地方對應的中文&#xff0c;此時…

win10下如何安裝ffmpeg

安裝ffmpeg之前先安裝win10 綠色軟件管理軟件&#xff1a;scoop. Scoop的基本介紹 Scoop是一款適用于Windows平臺的命令行軟件&#xff08;包&#xff09;管理工具&#xff0c;這里是Github介紹頁。簡單來說&#xff0c;就是可以通過命令行工具&#xff08;PowerShell、CMD等…

VVIC-商品詳情

一、接口參數說明&#xff1a; item_get-根據ID取商品詳情&#xff0c;點擊更多API調試&#xff0c;請移步注冊API賬號點擊獲取測試key和secret 公共參數 請求地址: https://api-gw.onebound.cn/vvic/item_get 名稱類型必須描述keyString是調用key&#xff08;點擊獲取測試k…

第一百一十三回 dart中的getter/setter方法

文章目錄 概念介紹使用方法示例代碼使用擴展 我們在上一章回中介紹了 flutter_screenutil包相關的內容&#xff0c;本章回中將介紹 dart中的setter/getter方法.閑話休提&#xff0c;讓我們一起Talk Flutter吧。 概念介紹 我們在這里介紹的setter/getter方法屬于編程語言中的…

【MongoDB】索引

目錄 一、概述 二、索引的類型 1、單字段索引 2、復合索引 3、其他索引 三、索引的管理 1、索引的創建 2、索引的查看 3、索引的刪除 四、索引的使用 1、執行計劃 2、涵蓋的查詢 一、概述 索引支持在MongoDB中高效地執行查詢。如果沒有索引&#xff0c;MongoDB必須…

Kubernetes pod調度約束[親和性 污點] 生命階段 排障手段

調度約束 Kubernetes 是通過 List-Watch 的機制進行每個組件的協作&#xff0c;保持數據同步的&#xff0c;每個組件之間的設計實現了解耦。 用戶是通過 kubectl 根據配置文件&#xff0c;向 APIServer 發送命令&#xff0c;在 Node 節點上面建立 Pod 和 Container。 APIServer…

springcloud3 hystrix實現服務降級,熔斷,限流以及案例配置

一 hystrix的作用 1.1 降級&#xff0c;熔斷&#xff0c;限流 1.服務降級&#xff1a; A方案出現問題&#xff0c;切換到兜底方案B&#xff1b; 2.服務熔斷&#xff1a;觸發規則&#xff0c;出現斷電限閘&#xff0c;服務降級 3.服務限流&#xff1a;限制請求數量。 二 案例…

ES6學習-Symbol

Symbol 數據類型Symbol&#xff0c;表示獨一無二的值。 對象的屬性名可有兩種類型&#xff0c;一種是原來的字符串&#xff0c;另一種是新增的 Symbol 類型 可以保證不與其他屬性名產生沖突。 let s1 Symbol() let s2 Symbol() console.log(s1, s2, s1 s2)//Symbol() Sy…

liunx exercise

云計算作業 Linux DAY1 1、創建alan1用戶&#xff0c;并使用root用戶切換用戶至alan1用戶。&#xff08;兩種方式切換【加-與不加-】&#xff0c;并總結其效果&#xff09; [rootlocalhost ~]# useradd alan1 [rootlocalhost ~]# su alan1 [alan1localhost root]$ pwd /roo…

FPGA學習——驅動WS2812光源并進行動態顯示

文章目錄 一、WS2812手冊分析1.1 WS2812燈源特性及概述1.2 手冊重點內容分析1.2.1 產品概述1.2.2 碼型及24bit數據設計 二、系統設計2.1 模塊設計2.2 模塊分析2.2.1 驅動模塊2.2.1 數據控制模塊 三、IP核設置及項目源碼3.1 MIF文件設計3.2 ROM IP核調用3.3 FIFO IP核調用3.4 項…

源碼斷點分析Spring的占位符(Placeholder)是怎么工作的

項目中經常需要使用到占位符來滿足多環境不同配置信息的需求&#xff0c;比如&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <beans xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xmlns"http://www.springframe…

InnoDB文件物理結構解析7 - FIL_PAGE_SDI

在數據庫系統中&#xff0c;通常包含數據字典(data dictionary)用于記錄數據庫對象的元數據(表&#xff0c;分區&#xff0c;觸發器&#xff0c;存儲過程&#xff0c;函數的定義)&#xff0c;我們可以通過information_schema(i_s)數據庫下的視圖(view)或者SHOW語句來訪問數據字…

【愛書不愛輸的程序猿】CPOLAR+HFS,低成本搭建NAS

歡迎來到愛書不愛輸的程序猿的博客, 本博客致力于知識分享&#xff0c;與更多的人進行學習交流 通過HFS低成本搭建NAS&#xff0c;并內網穿透實現公網訪問 - cpolar 極點云 前言1.下載安裝cpolar1.1 設置HFS訪客1.2 虛擬文件系統 2. 使用cpolar建立一條內網穿透數據隧道2.1 保留…

(三) 搞定SOME/IP通信之CommonAPI庫

本章主要介紹在SOME/IP通信過程中的另外一個IPC通信利劍,CommonAPI庫,文章將從如下幾個角度讓讀者了解什么是CommonAPI, 以及庫在實際工作中的作用 SOME/IP通信之CommonAPI CommonAPI庫是什么CommonAPI庫的編譯寫個Demo實戰一下CommonAPI庫是什么 CommonAPI是GENIVI組織開發…