標籤:param har 筆記 over 序列化 exception get 中繼資料 組合
net進階技術
一、多項目開發
1,添加對項目的引用
//建立一個類庫,用來放公用的要使用的類,使用的時候別的項目去引用它
//using 類庫檔案;
注意事項:注意被引用的類要使用public修飾
被引用的程式集中的類的修飾符,如果不寫的話,預設是internal。
效果是,只有當前程式集(類庫)內部才能訪問。
2,多項目時候的設定檔的讀取問題
a,只有主專案的設定檔才起作用(當前啟動的)
b,config檔案不能改名,不能建多個config,在config裡面也不能建多個AppSettings段
3,在項目中“轉到定義”,是看不到原始碼的,可以使用反編譯工具查看
4,調用第三方dll(類庫檔案)的方法
a,自己的項目就使用項目之間的引用方法
b,使用別人寫好的dll就用:添加引用-瀏覽-選擇要添加的dll檔案
二、索引器 indexer
1,索引器:沒有名字,索引器的內部本質
2,可以是唯讀或者唯寫
3,為什麼字串只能char ch = s[5];不能s[5] = ‘a‘
字串的不可變性;
唯讀索引
public char this[int index]{get;}
三、密閉類和靜態類
1,密閉類 sealed
不能有子類。適用於系統中的基本類,比如String類。可以new對象
2,靜態類 聲明為 static
沒法建立對象,沒法New;無法建立子類,只能聲明static成員(方法或者變數)
適用於工具類,不需要new,直接調用它的靜態方法或者屬性
3,擴充方法
使用方法:
聲明一個靜態類,增加一個靜態方法,第一個參數是被擴充類型,標記為this,
然後在其它類中可以直接調用,也可以使用普通靜態方法的方式調用,所以不能訪問private和protected成員。
四、深拷貝、淺拷貝
1,參考型別物件變數賦值的時候指向同一個對象
2,可以通過自訂一個拷貝方法賦值出來一個新的對象
3,如果對象之間有參考關聯性,如果拷貝的時候共用被引用的對象就是淺拷貝,如果被引用的對象也拷貝一份出來就是深拷貝
拷貝一個對象的引用,叫淺拷貝。
如果被引用的對象也拷被拷貝了,叫深拷貝
五、結構體 struct
是實值型別,拷貝副本,不能繼承,一個結構不能從另一個結構或者類繼承。但是,結構從基類Object繼承
struct Person
{
public int Age{get;set;}
public String Name{get;set;}
}
六、實值型別和參考型別
兩者之間的區別:
參考型別變數的賦值只複製對象的引用;參考型別在堆記憶體(malloc);
實值型別變數賦值會拷貝一個副本;實值型別在棧記憶體;
實值型別一定是sealed;
七、CTS,CLS,CLR,記憶體回收GC
一般型別系統CTS,Common Type System
通用語言規範CLS,Common Language Specification
通用語言執行平台CLR,Common Language Runtime
記憶體回收 GC, Garbage Collection
1,.Net平台下不只有C#語言,還有VB.Net、F#等語言。IL是程式最終編譯的可以執行的二進位代碼(Managed 程式碼)
不同的語言最終都編譯成標準的IL(中繼語言,MSIL);這樣C#就可以調用VB.Net寫的程式集(Assembly,dll、exe)
在.Net平台下:不同語言之間可以互聯互連、互相調用
2,不同語言中的資料類型各不相同,比如整數類型在VB.Net中是Integer、C#中是int。
.Net平台規定了通用資料類型(CTS,Common Type System),各個語言編譯器把自己語言的類型翻譯成CTS中的類型。
int是C#中的類型,Int32是CTS中的類型;int是C#中的關鍵字,但Int32不是
3,不同語言的文法不一樣,比如定義一個類A繼承自B的C#文法是class A:B{},VB.Net的文法是Class A Inherits B。
.Net平台規定了通用語言規範(CLS, Common Language Specification )
4,IL代碼由通用語言執行平台(CLR, Common Language Runtime )驅動運行,
CLR提供了記憶體回收
(GC, Garbage Collection,沒有任何引用的對象可以被自動回收,分析什麼時候可以被回收)、JIT(即時編譯器);
5,實值型別是放在“棧記憶體”中,參考型別放到“堆記憶體”,棧記憶體會在方法結束後自動釋放,“堆記憶體”則需要GC來回收
八、裝箱和拆箱
實值型別賦值給Object類型變數的時候,會發生裝箱:封裝成Object
Object類型變數賦值給實值型別的時候會發生拆箱,需要做顯示轉換。
int i = 10;//實值型別賦值
object obj = i;//裝箱,不需要進行顯示轉換,屬於隱式轉換
int j = obj;//這裡報錯,發生拆箱,需要進行顯示轉換 //int j = (int)obj;
注意:在拆箱的時候一定要顯示轉換回裝箱時候的資料類型,否則會報錯!!
九、比較相等的問題
1,查看兩個對象是否是同一個對象:對象1.RefrenceEquals(對象2);
2,String對象的==方法只是比較內容!
3,Object的Equals方法也比較兩個變數指向的是否是同一個對象;對象如果override了Equals方法,就可以進行內容的相同比較
4,預設情況下==不是調用Equals方法,需要重載==運算子
5,String等這些類是重寫了Equals方法
十、字串緩衝池
1,因為字串的不可變性,字串一旦被聲明,就會一直存在,直到GC判斷為未使用對象,被回收
2,字串是參考型別,程式中會存在大量的字串對象,會浪費記憶體、導致效能低下,
因此CLR提供了“字串緩衝池”,如果發現同樣內容的字串對象,再聲明時,直接拿來原來的對象
(對字串對象進行了重用)
string s1 = "rupeng";
string s2 = "rupeng";
string s3 = "ru" + "peng";
string s4 = new string(s1.ToCharArray());
string s5 = new string(new char[]{‘r‘,‘u‘,‘p‘,‘e‘,‘n‘,‘g‘});
Console.WriteLine(Object.ReferenceEquals(s1,s2));//true,字串緩衝池的作用,兩個字串引用指向同一個對象
Console.WriteLine(Object.ReferenceEquals(s1, s3));//true,編譯器最佳化,先進行拼接,後進行賦值
Console.WriteLine(Object.ReferenceEquals(s1, s4));//false
Console.WriteLine(Object.ReferenceEquals(s1, s5));//false
Console.WriteLine(Object.ReferenceEquals(s4, s5));//false
十一、ref和out
ref 方法參數的修飾符
1,方法內部修改外部變數的指向;
2,變數傳入前必須被賦值;
3,在方法中不是必須被賦值;
out 方法參數的修飾符
1,方法需要多個傳回值的時候使用
2,變數傳入前不用被賦值,賦值也沒用
3,在方法中必須對參數進行賦值
十二、委託
1,委託是一種資料類型,指向一個方法;委託是參考型別,變數可以是null
2,聲明委託的方式:
delegate 傳回值類型 委託名(參數1,參數2,。。。);比如:delegate void MyDel(int n)
注意:這裡除了前面的delegate,剩下部分和聲明一個函數一樣,但是MyDel不是函數名,而是委託類型名
3,可以聲明一個變數,指向和它類型相容的方法
4,如何建立委託類型的對象:
MyDel sp = new MyDel(SayHello);
注意:
SayHello需要和MyDel的參數和傳回值一樣;
sp這個委託變數就指向SayHello這個方法,不要寫成new MyDel(SayHello()),因為加上()就是調用方法了
5,簡化的方法:
MyDel sp = SayHello;//編譯器會給搞成new MyDel(SayHello)
注意不要寫成MyDel sp = SayHello();
6,委託的使用:
委託變數之間是可以互相賦值的,就是一個傳遞指向方法的過程;
sp()就是調用指向的方法,如果有參數就傳遞參數
程式碼範例:
public delegate void MyDel(int n);//第一步,聲明一個委託
static void M1(int a)//定義一個方法,方法的參數和傳回值要和委託對應
{
Console.WriteLine("M1"+a);
}
MyDel d1 = new MyDel(M1);//聲明一個MyDel類型的變數,指向一個指向M1方法的對象
//上面的代碼可以簡化成 MyDel d1 = M1;
注意:委託是參考型別,可以為null,如果委託變數是null,那麼如果調用的話,就會拋出異常:NullReferenceException;
7,Func、Action
.Net中內建兩個泛型委派Func和Action(在“物件瀏覽器”的mscorlib的System下),日常開發中基本不用自訂委託類型了
Func是有傳回值的委託,Action是沒有傳回值的委託
8,匿名方法
使用Delegate的時候很多時候沒有必要使用一個普通的方法,因為這個方法只有這個Delegate會用,並且只用一次,這個時候使用匿名方法最合適
匿名方法就是沒有名字的方法
範例程式碼:
MyDelegate p = delegate(int s){s = 10;};
9,lambad運算式
函數式編程,在EntityFramework編程中用的很多
1,Action<int> a1 = delegate (int i){Console.Write(i);};
2,可以簡化為:
Action<int> a2 = (int i)=>{Console.Write(i);};//(=>讀作goes to)
3,還可以省略參數類型(編譯器會自動根據委託類型推斷)
Action<int> a3 = (i)=>{Console.Write(i);};
4,如果只有一個參數還可以省略參數的小括弧(多個參數不行)
Action<int> a4 = i=>{Console.Write(i);};
5,如果委託有傳回值,並且方法體只有一行代碼,這一行代碼還是傳回值,那麼久可以連方法的大括弧和return都省略
原本的:Func<int,int,string> f1 = delegate (int i,int j){return "結果是"+(i+j);};
簡化為:Func<int,int,string> f2 = (i,j) =>"結果是"+(i+j);
普通匿名型別也是一樣用lambda運算式
6,委託深入
集合常用擴充方法:
Where(支援委託)、Select(支援委託)、Max、Min、OrderBy
First(擷取第一個,如果沒有則異常)
FirstOrDefault(擷取第一個,如果一個都沒有則返回預設值)
Single(擷取唯一一個,如果沒有或者多個則異常)
SingleOrDefault(擷取唯一一個,如果沒有則返回預設值,多個則異常)
ToList、ToArray
7,委託的組合
委派物件可以“+相加”,調用組合後的新委派物件會一次調用被組合取來的委託:MyDel m5 = m1+m2+m3;
組合的委託必須是同一個委託類型
委託的“-”則是從組合委託中把委託移除;
委託如果有傳回值,則有一些特殊。委託的組合一般是給事件用的,用普通的委託的時候很少用
8,事件
事件文法:event MyDelegate md1;
加了event關鍵字實現事件機制的好處:用了event事件,不可以修改事件已經註冊的值;不可以冒充進行事件通知了。只能+=、-=
9,委託與事件總結
委託的作用:
佔位,在不知道將來要執行的方法的具體代碼時,可以先用一個委託變數來代替方法調用(委託的傳回值,參數列表要明確)。
在實際調用之前,需要為委託賦值,否則為null
事件的作用:
事件的作用與委託變數一樣,只是功能上比委託變數有更多的限制。
比如:
1,只能通過+=或-=來Binder 方法(事件處理常式)
2,只能在類內部調用(觸發)事件
(面試題)事件和委託的關係:事件由一個私人的委託變數和add_***和remove_***方法組成
事件的非簡化寫法:聲明一個私人的委託變數和add、remove方法
10,委託和事件的區別和關係
錯誤的說法“事件是一種特殊的委託”
委託用的比較多,事件只有開發WinForm、WPF的時候用的才比較多
事件、索引器、屬性本質上都是方法。
(面試題)介面中可以定義什嗎?
介面中只可以定義方法。介面中可以定義“事件、索引器、屬性”,因為他們本質上也都是方法。
十三、反射
1,反射的作用:動態建立對象、動態賦值、動態調用方法
2,反射簡介
1,.Net中的類都被編譯成IL,反射就可以在運行時獲得類的資訊(有哪些方法、欄位、建構函式、父類是什麼等等),
還可以動態建立對象、調用成員
2,每個類對應一個Type對象,每個方法對應一個MethodInfo對象,每個屬性對應一個PropertyInfo……。
這些就是類、方法、屬性的“中繼資料”(meta data)。
對象和這個類的對象沒有直接關係。
這些“中繼資料對象”和成員有關,和對象無關,也就是每個成員對應一個對象。
3,類別中繼資料Type
1,使用寫好的Person類
1,擷取類資訊對象Type的方法:
從對象擷取:Type type = person.getType();
從類名擷取:Type type =typeof(Person); (type 是關鍵字,不是方法)
從全類名(命名空間+類名)擷取:Type type = Type.GetType("com.rupeng.Person");
2,為什麼要有這麼多擷取方式?
主要根據要查詢的內容一樣,方式也就不一樣。
如果有一個對象,就用getType()。
如果沒有對象就可以用typeof;
如果要運行時通過設定檔等拿到的字串來擷取就要用Type.GetType("com.rupeng.Person");
3,Activator.CreateInstance(type)
//使用無參數構造方法建立此類的對象(如果沒有無參建構函式會報異常)。
要求類必須有無參建構函式。 相當於new Person() 是閑的蛋疼嗎?
2,父類中GetType()返回的是什嗎?this代表“當前對象”,不是“當前類”
3,Type的成員方法
1,IsInterface、IsArray、IsPrimitive、 IsEnum:是否介面、數組、原始類型、枚舉等。
2,String Name得到類名(不包含命名空間);String FullName包含命名空間
3,BaseType得到父類的Type。
4,Type的成員
1,建構函式
ConstructorInfo GetConstructor(Type[] types)//擷取參數類型匹配的建構函式
ConstructorInfo[] GetConstructors()//獲得所有的public建構函式,包括父類的
調用object Invoke(object[] parameters)可以調用建構函式
2,方法
MethodInfo GetMethod(string name, Type[] types)
MethodInfo[] GetMethods() //獲得所有的public方法
調用object Invoke(object obj, object[] parameters)可以調用方法
3,屬性
PropertyInfo GetProperty(string name) 擷取某個屬性
PropertyInfo[] GetProperties() 擷取所有屬性
PropertyInfo的主要成員:
CanRead、 CanWrite是否可讀寫; GetValue、 SetValue讀寫值(第一個參數是要在哪個對象要調用)
4,常用的Attribute(特性)
[Obsolete] 表名此成員已淘汰
當使用PropertyGrid的時候可以修飾屬性
[ReadOnly(true)]在編輯器中唯讀,代碼賦值不受影響;
[DisplayName("姓名")] 屬性的顯示名;
[Browsable(false)]屬性是否可見
1,Attribute文法
Attribute用來在代碼中附加一些元資訊,這些原資訊可被編譯器,.NetFramework,或者我們的程式使用。
方法、屬性、類上都可以標註Attribute
一般起到說明、配置的作用;命名一般以Attribute結尾,如果以Attribute結尾的話使用的時候可以省略Attribute
註解不會直接影響代碼的實際邏輯,僅僅起到輔助性作用;如果起作用也是編譯器、.NetFramework、程式去解析的
在Type、MethodInfo、PropertyInfo等上都可以調用object[] GetCustomAttributes(Type attributeType,bool inherit)擷取標註的註解對象
因為同一個Attribute可能標註多次,所以傳回值是數組
十四、Regex
1,Regex是對字串進行匹配的文法,用來判斷一個字串是否符合某個規則
2,基本元字元:
a,. 表示除了\n以外的任意的單個字元
b,[0-9]表示的是0-9之間的任意一個整數數字;[a-z]任意一個小寫字母;[A-Z]任意一個大寫字母
c,\d表示數字,\D表示非數字,\s表示空白,\S表示非空白,\w表示小寫字母或數字和漢字
\W表示特殊符號
d,\ 表示對於 . 等特殊字元轉義
e,()提升優先順序別和提取組
f,[]代表一個區間中的任意一個:[abc\d]就代表abc或者數字中的任意一個字元
g,| 代表或者
h,+ 是出現1次或者無限次
i,* 是出現0次或者無限次
j,? 是出現0次或者1次
k,{5}出現5次,{1,2}出現一次或者兩次,{5,8}出現5次至8次,
{1,}最少出現1次,{3,}最少出現3次
l,^ 以。。開始;$以。。結束
使用Regex.isMatch("目標字串",@"Regex");//傳回值是bool類型
提取://使用()進行分組,然後調用match.Groups[0].Value進行取值
Match match = Regex.Match("2016-12-29", @"^(\d{4})\-(\d{1,2})\-(\d{1,2})$");
範例程式碼:
Console.WriteLine( Regex.IsMatch("2016-12-29", @"^\d{4}\-\d{1,2}\-\d{1,2}$") );
Match match = Regex.Match("2016-12-29", @"^(\d{4})\-(\d{1,2})\-(\d{1,2})$");
if (match.Success)
{
string year = match.Groups[0].Value;
string month = match.Groups[1].Value;
string day = match.Groups[2].Value;
Console.WriteLine("年"+year+"月"+month+"日"+day);
}
else
{
Console.WriteLine("匹配不成功");
}
Console.ReadKey();
十五、對象的序列化
對象序列化是將對象轉換成為位元據(位元組流),還原序列化是將其還原為對象。
用處,避免程式重啟等情況造成的資料丟失,不僅程式重啟、作業系統重啟會造成對象的消失,就連退出函數範圍等都可能造成對象的消失
序列化和還原序列化就是為了保持對象的持久化
注意:一個對象想能序列化,必須標註成[Serializable],其父類和相關的欄位、屬性都要標記成“可序列化”
序列化只會對類中的欄位序列化(只序列化一些狀態資訊)
類結構改變後,之前序列化的內容盡量不用,否則可能會出錯!
使用:
BinaryFormatter類有兩個方法:
void Serialize(Stream stream, object pbj)
對象obj序列化到Stream中
object Deserialize(Stream stream)
將對象從stream中還原序列化,傳回值為還原序列化得到的對象
為什麼要序列化:
保持對象的持久化,將一個複雜的對象轉換流,方便我們的儲存與資訊交換
應用:
Asp.net中進程外Session要求對象可序列化
還有Xml序列化,應用開發中Json序列化已經代替了二進位序列化和Xml序列化等
十六、XML(可延伸標記語言 (XML))
1,XML優點:
容易讀懂;格式標準任何語言都內建了XML分析引擎,不用單獨進行檔案分析引擎的編寫
2,是一種格式化的方式來儲存資料,可以用記事本、瀏覽器開啟
3,.Net程式中的一些設定檔app.config、web.config檔案都是xml檔案
4,文法規範:
標籤/節點(Tag/Node)、嵌套(Nest)、屬性。標籤要閉合,屬性值要用“”包圍,標籤可以互相嵌套
XML樹,父節點、子節點、兄弟節點(siblings)
xml編寫完成以後可以用瀏覽器來查看,如果寫錯了瀏覽器會提示。如果明明沒錯,瀏覽器還是提示錯誤,則可能是檔案編碼問題。
5,文法特點:
嚴格區分大小寫;
有且只有一個根節點
有開始標籤必須有結束標籤,除非自閉和(沒有內容的時候)<Person/>
屬性必須使用雙引號
(可寫可不寫,寫了檔案類型的時候要注意實際儲存的檔案類型需要一致)
文檔聲明:
<?xml version="1.0" encodeing="utf-8"?>
注釋:
<!--要注釋的內容-->
6,注意編碼問題,文字檔實際編碼與文檔聲明中的編碼一致
7,讀取xml檔案:
<Person>
<Student StuID="11">
<StuName>張三</StuName>
</Student>
<Student StuID="22">
<StuName>李四</StuName>
</Student>
</Person>
XmlDocument doc = new XmlDocument();//建立一個讀取器對象
doc.Load(@"xml檔案的路徑");//載入xml檔案
XmlNodeList students = doc.DocumentElement.ChildNodes;//拿到xml檔案的節點集合
foreach(XmlNode stu int students)
{
XmlElement element = (XmlElement)stu;
string stuId = element.GetAttribute("StuID");
XmlNode nameNode = element.SelectSingleNode("StuName");//擷取Person接線的Name
string name = nameNode.innerText;
Console.WriteLine(stuId+","+name);
}
8,產生XML檔案
XmlDocument doc = new XmlDocument();//建立XML檔案對象
XmlElement ePersons = doc.CreateElement("Persons");//建立根節點對象
doc.AppendChild(ePersons);//將根節點對象添加到XML檔案對象
foreach(Person person in ePersons)
{
XmlElement ePerson = doc.CreateElement("Person");
ePerson.SetAttribute("id",person.id.ToString());
XmlElement eName = doc.CreateElement("Name");
eName.InnerText = person.Name;
XmlElement eAge = doc.CreateElement("Age");
eAge.InnerText = person.Age.ToString();
ePerson.AppendChild(eName);//給ePerson添加子節點eName
ePerson.AppendChild(eAge);//給ePerson添加子節點eAge
ePersons.AppendChild(ePerson);//將ePerson添加給根節點
}
doc.Save("檔案全路徑");
class Person
{
public Person(int id, string name, int age)
{
this.Id = id;
this.Name = name;
this.Age = age;
}
public int Id { set; get; }
public string Name { set; get; }
public int Age { set; get; }
}
Person[] persons = { new Person(1, "rupeng", 8), new Person(2, "baidu", 6) };
如鵬網學習筆記(三).Net進階技術