国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

C#學(xué)習(xí)筆記--數(shù)據(jù)結(jié)構(gòu)、泛型、委托事件等進階知識點

這篇具有很好參考價值的文章主要介紹了C#學(xué)習(xí)筆記--數(shù)據(jù)結(jié)構(gòu)、泛型、委托事件等進階知識點。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

C#進階

簡單數(shù)據(jù)結(jié)構(gòu)類

ArrayList

元素類型以O(shè)bject類型存儲,支持增刪查改的數(shù)組容器。

因而存在裝箱拆箱操作,謹慎使用。

//ArrayList
ArrayList array=new ArrayList();
//增=================
array.Add("Hello");
array.Add(true);
array.Add("Tony");//添加單個元素
array.Add("Hello");
array.Add("World");

ArrayList array2=new ArrayList();
array2.Add("123");
array.AddRange(array2);//從數(shù)組添加元素

//插入
array.Insert(1,"456");

//刪除==================
array.Remove("Hello");
array.RemoveAt(1);//根據(jù)索引移除元素
array.Clear();//清空
//查=================
array[0];
//查看元素是否存儲在
if(array.Contains(true))
{
    
}
//正向查找某個元素
//返回索引  未找到則返回-1
array.IndexOf("Hello");
//反向查找元素位置
array.LastIndexOf("Hello");
//改=======================
array[2]="123";

//遍歷======
//區(qū)別長度(已經(jīng)使用的容量)和容量
//容量
array.Capacity;
for(int i=0;i<array.Count;i++)
{
    Console.WriteLine(array[i]);
}
//迭代器遍歷
foreach(object obj in array)
{
    Console.WriteLine(item);
}
//裝箱拆箱

ArrayList和數(shù)組區(qū)別?

  1. ArrayList使用不用說明固定長度,數(shù)組則需要
  2. 數(shù)組存儲的是指定類型的,ArrayList是Object
  3. ArrayList存在裝箱拆箱,數(shù)組不存在
  4. ArrayList數(shù)組長度用Count獲取 而數(shù)組長度為Length
  5. ArrayList中提供增刪方法,使用方便,數(shù)組需要自己操作實現(xiàn)

Stack

stack的本質(zhì):也是Object數(shù)組

//棧 先進后出
//聲明
Stack stack=new Stack();

//========增===壓棧
stack.Push(1);
stack.Push("23");
stack.Push("Tony");
stack.Push(66.6);
//=======取====彈棧
object o=stack.Pop();
//======查
//棧只能查看棧頂?shù)膬?nèi)容,無索引器不可根據(jù)索引查看
Object look=stack.Peek();
//查看元素中有無內(nèi)容
if(stack.Contains("Tony"))
{
	Console.WriteLine("該元素存在!");    
}

//清空
stack.Clear();
//遍歷
foreach(object item in stack)
{
    Console.WriteLine(item);
    //從棧頂取元素
}
//將棧轉(zhuǎn)換為數(shù)組
object[] stackArray=stack.ToArray();
//棧頂元素在數(shù)組前部分
//循環(huán)彈棧
while(stack.Count>0)
{
    object obj=stack.Pop();
    Console.WriteLine(obj);
}
//存在裝箱拆箱

Queue

本質(zhì):也是一個object數(shù)組

//隊列  先進先出
//聲明
Queue queue=new Queue();

//增
queue.Enqueue(1);
queue.Enqueue(3.15f);
queue.Enqueue("Tony");
//取
queue.Dequeue();
//查
queue.Peek();
if(queue.Contains(3.15f))
{
    //打印
}
//改 只能清空
queue.Clear();
//遍歷 
queue.Count();
foreach(object item in queue)
{
    Console.WriteLine(item);
}
//轉(zhuǎn)成數(shù)組
object[] objs=queue.ToArray();
for(int i=0;i<objs.Length;i++)
{
    //打印
     Console.WriteLine(objs[i]);
}
//循環(huán)出列
while(queue.Count>0)
{
    object obj=queue.Dequeue();
    Console.WriteLine(obj);
}

Hashtable

本質(zhì):存儲也是以object存儲。散列表 ,基于hash代碼組織起來的鍵值對

可以做到訪問效率是O(1)

//HashTable
//聲明
Hashtable hashtable=new  Hashtable();

//增加  鍵不能重復(fù)
hashtable.Add(1,"123");
hashtable.Add("name","TonyChang");
hashtable.Add(3,21);
//刪除 --只能通過鍵來刪除
hashtable.Remove(1);
hashtable.Remove("name");

//清空
hashtable.Clear();

//查看 找不到為空
hashtable[1];
hashtable["name"];

//驗證是否存在
if(hashtable.Contains("name"))
{
   //根據(jù)鍵去查找
}
if(hashtable.ContainsKey("name"))
{
    //根據(jù)鍵去查找
}
if(hashtable.ContainsValue("TonyChang"))
{
    //根據(jù)值去查找
}
//只能通過鍵來找值,反之不行

//遍歷
hashtable.Count;//鍵值對數(shù)
//不一定按照插入順序打印
//元素是無序的
foreach(object item in hashtable.Keys)
{
    Console.WriteLine("鍵"+item);
    Console.WriteLine("值"+hashtable[item]);
}
//遍歷值
foreach(object item in hashtable.Values)
{
    Console.WriteLine("值"+item);
}
//鍵值對遍歷
foreach(DictionaryEntry item in hashtable)
{
    Console.WriteLine("鍵"+item.Key+" 值"+item.Value);
}
//迭代器遍歷
IDictionaryEnumerator tcIDE=hashtable.GetEnumerator();
bool flag =tcIDE.MoveNext();
while(flag)
{
     Console.WriteLine("鍵"+tcIDE.Key+" 值"+tcIDE.Value);
     flag =tcIDE.MoveNext();
}
//存在裝箱拆箱

泛型

泛型

泛型實現(xiàn)了類型參數(shù)化,達到代碼重用目的,通過類型參數(shù)化來實現(xiàn)同一份代碼操作多種類想,

泛型相當(dāng)于類型占位符,定義類或者方法時使用替代符代表變量類型,

當(dāng)真正使用類或方法時候再具體指定類型

泛型分類:泛型類,泛型方法,泛型接口

//泛型
class TestClass<T>
{
    public T value;
}
TestClass<int> t=new TestClass<int>();
t.value=666;

//泛型占位符可以有多個
class TestClass2<T1,T2,K,M>
{
    public T1 value1;
    public T2 value2;
    public K value3;
    public M value4;
}
interface ITest<T>
{
    T Value
    {
        get;
        set;
    }
}
//繼承之后需要表明具體類類型
class Demo:ITest<int>
{
    public int Value
    {
        get;
        set;
    }
}

//泛型方法
class Test2
{
    public void TestFun<T>(T value)
    {
        Console.WriteLine(value);
    }
    public void TestFun<T>()
    {
        T t=default(T);
    }
    //作為返回值
    public T fun3<T>()
    {
        return default(T);
    }
}

Test2 tt=new Test2();
tt.TestFun<string>("Tony");

//泛型類中的泛型方法
class Test2<T>
{
    public T value;
    public void TestFun(T value)
    {
        //這是非泛型方法
    }
    //泛型方法
    //判斷"<>"有無
    public void fun4<K>(K value)
    {
        //打印        
    }
}

泛型約束

泛型約束:關(guān)鍵字 where

  1. 值類型 where T :struct
  2. 引用類型 where T :class
  3. 存在無參公共構(gòu)造函數(shù) where T :new ()
  4. 某個類本身或者其派生類 where T:類名
  5. 某個接口的派生類型 where T:接口名
  6. 另一個泛型類型本身或者派生類型 where T:另一個泛型字符

注:這里的”T“ 可以換成其它的泛型字母

//泛型類型的約束
class Test<T> where T:struct
{
    public void fun1<M> where M:struct
    {
        
    }
}

class Test1<T> where T:class
{
    public void fun1<M> where M:struct
    {
        
    }
}
//注意抽象類的無參公共構(gòu)造函數(shù)
//也被允許
class Test2<T> where T:new()
{
    public void fun1<M> where M:struct
    {
        
    }
}
//······
//約束的組合使用
class Test7<T> where T:class,new ()
{
    
}
//多個泛型有有約束
class Test8<T,K> where T:class,new() where K:struct
{
    
}

常用的泛型數(shù)據(jù)結(jié)構(gòu)類

list

本質(zhì):泛型數(shù)組

//List
List<int> list=new List<int>();
//添加
list.Add(1);
list.Add(2);
list.Add(3);
list.Add(4);
//查
list[0];
//清空
list.Clear();
//移除
list.RemoveAt(1);
//查看某個元素是否存在
if(list.Contains(1))
{
 	//該元素存在   
}
//查找元素索引
//未找到返回-1
int index=list.IndexOf(4);
//反向查找
//未找到返回-1
index=list.LastIndexOf(4);
//改
list[2]=66;

//插入
list.Insert(0,666);
//遍歷
//長度
list.Count;
//容量
list.Capacity;
for(int i=0;i<list.Count;i++)
{
    //打印
    Console.WriteLine(list[i]);
}
foreach(int item in list)
{
     Console.WriteLine(item);
}
//List指定類型 不存在裝箱拆箱

DIctionary

本質(zhì):有具體類型的hashtable

//Dictionary
//聲明
Dictionary<int,string> dictionary=new Dictionary<int,string>();
//增
dictionary.Add(1,"Hello");
dictionary.Add(2,"World");
dictionary.Add(3,"Tony");
dictionary.Add(4,"Chang");
//刪除
dictionary.Remove(1);
//清空
dictionary.Clear();
//查
//按鍵進行查
dictionary[3];
dictionary[5];//找不到則報錯?。。?//查看是否存在
if(dictionary.ContainsKey(1))
{
    //存在
}
if(dictionary.ContainsValue("Tony"))
{
    //存在
}
//改
dictionary[1]="258";
//遍歷
dictionary.Count;//元素個數(shù)
foreach(int item in dictionary.Keys)
{
    Console.WriteLine(item);
    Console.WriteLine(dictionary[item]);
}
//遍歷所有類型的值
foreach(int item in dictionary.Values)
{
    Console.WriteLine(item);
}
//鍵值對一起查找
foreach(KeyValuePair<int,string> item in dictionary)
{
    Console.WriteLine("鍵:"+item.Key+"值:"+item.Value);
}

順序存儲和鏈?zhǔn)酱鎯?/h4>

數(shù)據(jù)結(jié)構(gòu)

線性表:數(shù)組、鏈表、棧、隊列

非線性表:樹、圖、堆、散列表

存儲結(jié)構(gòu):

  • 順序存儲
    • 數(shù)組,List,ArrayList
    • Stack
    • Queue
  • 鏈?zhǔn)酱鎯?
    • 單向鏈表
    • 雙向鏈表
    • 循環(huán)鏈表
//簡單的單向鏈表
//節(jié)點類
class LinkedNode<T>
{
    public T value;
    public LinkedNode<T> nextNode;
    public LinkedNode(T value)
    {
        this.value=value;
    }
}
//單向鏈表的簡單實現(xiàn)
class LinkdedList<T>
{
    public LinkedNode<T> head;
    public LinkedNode<T> last;
    public void Add(T value)
    {
        LinkedNode<T> node=new LinkedNode<T>(value);
        if(head==null)
        {
            head=node;
            last=node;
        }
        else
        {
            last.nextNode=node;
            last=node;
        }
    }
    public void Remove(T value)
    {
        if(head==null)
        {
            return;
        }
        if(head.value.Equals(value))
        {
            //如果只有一個節(jié)點
            //且還是要刪除的節(jié)點
            head=head.nextNode;
            if(head==null)
            {
                last==null;
            }
            return;
        }
        LinkedNode<T> node=head;//哨兵節(jié)點
        //走到目標(biāo)節(jié)點前的一個節(jié)點
        while(node.nextNode!=null)
        {
            if(node.nextNode.value.Equals(value))
            {
                break;
            }
            node=node.nextNode;
        }
        //進行移除
        node.nextNode=node.nextNode.nextNode;
    }
}

鏈?zhǔn)胶蛿?shù)組的優(yōu)缺點:

鏈?zhǔn)奖淼脑觥h比較方便,只需要更改節(jié)點之間的聯(lián)系即可。

數(shù)組表查找比較方便,可以根據(jù)索引直接定位到某個位置。

LinkedList

有類型的雙向鏈表。

//雙向鏈表
LinkedList<int> linkedList=new LinkedList<int>();

//增
//從尾部添加
linkedList.AddLast(10);
//從頭部加
linkedList.AddFirst(5);

//移除
linkedList.RemoveFirst();//移除頭節(jié)點
linkedList.RemoveLast();//移除尾節(jié)點
//移除元素
linkedList.Remove(5);

//清空
linkedList.Clear();

//查
//頭節(jié)點
LinkedListNode<int> first=linkedList.First;
//尾節(jié)點
LinkedListNode<int> last=linkedList.Last;

//找到某個節(jié)點
LinkedListNode<int> node=linkedList.Find(5);//找不到返回為null
//在某個節(jié)點之后添加一個節(jié)點
linkedList.AddAfter(node,15);
//在某個節(jié)點之后前添加一個節(jié)點
linkedList.AddBefore(node,12);

//判斷某一元素是否存在
if(linkedList.Contains(5))
{
    //鏈表中存在5
}

//改
//找到某一節(jié)點
//改變其數(shù)值
//找到某個節(jié)點
LinkedListNode<int> node1=linkedList.Find(5);//找不到返回為null
node1.Value=15;

//遍歷
foreach(int item in linkedList)
{
    //打印節(jié)點
    Console.WriteLine(item);
}

//從頭節(jié)點進行遍歷查找
LinkedListNode<int> curNode=linkedList.First;
while(curNode!=null)
{
 	Console.WriteLine(curNode.Value);  
    curNode=curNode.Next;
}
//從尾部節(jié)點進行遍歷查找
LinkedListNode<int> curNode=linkedList.Last;
while(curNode!=null)
{
 	Console.WriteLine(curNode.Value);  
    curNode=curNode.PreVious;
}

泛型棧和隊列

Stack<int> stack;

Queue<int> queue;

具體的api和非泛型的相同。不再贅述!


委托與事件

委托

委托是函數(shù)的容器,可以理解為表示函數(shù)的變量類型,用來存儲、傳遞函數(shù)。

委托的本質(zhì)是一個類,用來定義函數(shù)的類型(返回值和參數(shù)的類型)

不同的函數(shù)必須對應(yīng)各自“格式”的委托。

關(guān)鍵字:delegate

存在位置:namespace 中(一般在此處),class中

//委托
//帕斯卡命名法
delegate void MyFuns();//無參無返回值的委托(此類型函數(shù)的家)
delegate int MyFuns2(int a);//不可以重名?。?!盡管類型不同也不可以
//默認為public的,一般不用private

class Program
{
    static void Main(string[] args)
    {
        //將Fun函數(shù)放入委托容器中
        MyFuns funs=new MyFuns(Fun);
        //調(diào)用委托(中的函數(shù))
        funs.Invoke();
        //======或者
        MyFuns f2=Fun;//聲明委托
        f2();//調(diào)用委托
        //============================
        MyFuns2 funs2=new MyFuns2(Fun2);
        funs2.Invoke(2);  
       
        MyFuns2 f2=Fun2;//聲明
        f2(2);//調(diào)用
    }
    static void Fun()
    {
        Console.WriteLine("我是個函數(shù)!");
    }
    static void Fun4()
    {
        Console.WriteLine("我是個函數(shù)Fun4!");
    }
    static int Fun2(int a)
    {
        Console.WriteLine("我是另外一種類型函數(shù)");
        return a*2;
    }
}

委托變量是函數(shù)的容器:

委托常用在:

  1. 作為類的成員
  2. 作為函數(shù)的參數(shù)
//接上一個代碼塊
class Test
{
    public MyFuns funs;
    public MyFuns2 funs2;
    //委托作為函數(shù)的參數(shù)
    public void TestFun(MyFuns funs,MyFuns2 funs2)
    {
        //先處理一些邏輯
        //邏輯 code
        //······
        //再執(zhí)行委托方法
       this.funs=funs;
       this.funs2=funs2;
    }
}
//在上個代碼塊Main中調(diào)用
//使用
Test t=new Test();
t.TestFun(Fun,Fun2);//傳遞的函數(shù)名字

委托中存儲多個函數(shù)(多播委托)

//多播委托
MyFuns funs3=null;
fun3+=Fun;
fun3+=Fun4;
fun3.Invoke();//執(zhí)行
//本質(zhì):觀察者模式====
//老板來了!可以執(zhí)行委托,通知存儲在委托中的員工好好工作的函數(shù)執(zhí)行。
//老板走了!可以執(zhí)行另一種委托,通知存儲在委托中的員工開始摸魚。(狗頭)
//委托輕松實現(xiàn)!

小點:委托中多次減去同一個函數(shù),不會報錯。

委托執(zhí)行之前最好要檢查是否為空!

系統(tǒng)提供的委托:

//系統(tǒng)定義好的委托
//Action是無參無返回值類型的委托
Action action=Fun;
action+=Fun4;
action();//執(zhí)行

//可以傳參數(shù)無返回值的委托
Action<int> ac1;
Action<int,float> ac2;
//=========Action無返回值委托===========
//=========Func有返回值=================
//Func委托
Func<int> funcInt;//返回值為int 無參數(shù)的委托
Func<int,float> func2;//參數(shù)為int 返回值為float的委托
funcInt+=Funs;
static int Fun5()
{
    Console.WriteLine("我是函數(shù)Fun5");
    return 5;
}

//自定義泛型委托
delegate T MyFun3<T>(T value);

C#學(xué)習(xí)筆記--數(shù)據(jù)結(jié)構(gòu)、泛型、委托事件等進階知識點

相當(dāng)于給每個裝在進委托中的函數(shù)來一次單獨的分配一個新的委托,各自的函數(shù)都存入自己獨立的委托,然后調(diào)用單獨的委托便會執(zhí)行在委托中的函數(shù)。(對foreach遍歷的理解)

委托練習(xí):

大耳朵圖圖一家吃飯!

使用托通知大家吃飯。

namespace TC
{
  abstract class Person
    {
        public string name;
        public abstract void Eat();
    }
    class Father : Person
    {
        public Father(string name)
        {
            this.name = name;
        }
        public override void Eat()
        {
            Console.WriteLine("{0}來吃飯了", name);
        }
    }
    class Mother : Person
    {
        public Action ToEat;
        public Mother(string name)
        {
            this.name = name;
        }
        public override void Eat()
        {
            Console.WriteLine("{0}來吃飯了", name);
        }
        public void Cooking()
        {
            Console.WriteLine("{0}正在做飯,",name);
            Console.WriteLine("做完了");
            ToEat?.Invoke();
            Eat();
        }
    }
    class Son : Person
    {
        public Son(string name)
        {
            this.name = name;
        }
        public override void Eat()
        {
            Console.WriteLine("{0}來吃飯了", name);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Father father = new Father("胡英俊");
            Mother mother = new Mother("張小麗");
            Son son = new Son("胡圖圖");
            mother.ToEat += father.Eat;
            mother.ToEat += son.Eat;
            mother.Cooking();
        }
    }
}

C#學(xué)習(xí)筆記--數(shù)據(jù)結(jié)構(gòu)、泛型、委托事件等進階知識點

事件

事件是基于委托的存在,是安全的委托。

事件的使用:

  1. 事件是作為成員變量存在于子類中
  2. 其它用法和委托相同

事件和委托的不同之處:事件不能在類外部賦值(但可以進行+=,-=)和調(diào)用。(事件必須在類中賦值和使用)

注意:它只能作為成員存在于類和接口以及結(jié)構(gòu)體中。

class Test
{
    //委托
    public Action myAction;
    //事件
    public event Action myEvent;
}

為什么要用事件呢?

  1. 防止外部隨意的置空委托
  2. 防止外部隨意調(diào)用委托
  3. 事件對委托進行一次的封裝,使用更安全

匿名函數(shù)

匿名函數(shù)沒有函數(shù)名字,往往都配合事件和委托使用的。

基本語法:

delegate(參數(shù)列表)``{

//函數(shù)邏輯

};

何時使用:

  1. 函數(shù)中傳遞委托參數(shù)時
  2. 委托或事件賦值時候
//匿名函數(shù)
//無參 無返回
Action action = delegate()
{
   //匿名函數(shù)的聲明
    //匿名函數(shù)聲明,放置在委托容器中
    Console.WriteLine("我是匿名函數(shù)");
};
action();//調(diào)用委托時候 調(diào)用匿名函數(shù)

//有參 無返回值
Action<int,string> action2=delegate(int a,string b)
{
    Console.WriteLine(a);
    Console.WriteLine(b);
};//注意:匿名函數(shù)最后加分號
action2(100,"Tony");
//有返回值 無參數(shù)
Func<int> action3=delegate()
{
    return 666;
};
action3();
//一般情況下會作為函數(shù)參數(shù)傳遞
class Test
{
    public Action action;
    
    //作為參數(shù)
    public void DoSomething(int a,Action ac)
    {
        Console.WriteLine(a);
        ac();
    }
    //作為返回值
    public void GetFun()
    {
        return delegate(){
          //無參數(shù)無返回值的匿名函數(shù)
            //作為函數(shù)的返回值
        };
    }
}

//使用
Test t=new Test();
t.DoSomething(100,delegate(){
   Console.WriteLine("隨函數(shù)傳入的匿名函數(shù)邏輯"); 
});
//接受返回的匿名函數(shù)
Action ac3=t.GetFun();
//執(zhí)行
ac3();
//或者一步到位
t.GetFun()();
//匿名函數(shù)的缺點:
//匿名函數(shù)添加到委托中,因為沒有名字,不方便進行管理。
//不能指定移除某個匿名函數(shù)

Lambda表達式

lambda只是匿名函數(shù)的簡寫形式,本質(zhì)還是匿名函數(shù)

//Lambda表達式
//無參無返回值
Action action=()=>{
    Console.WriteLine("無參無返回值的");
};
//執(zhí)行
action();

//====有參數(shù) 無返回值
Action action2=(int value)=>
{
    Console.WriteLine("有參無返回值的Lambda{0}",value);
};
//調(diào)用執(zhí)行
action2(666);

//可以省略參數(shù)類型,參數(shù)類型和存儲其的容器(事件或委托)來判斷
Action<int> action3=(value)=>{
    Console.WriteLine("省略了參數(shù)類型的Lambda表達式的寫法{0}",value);
};
action(999);
//======有返回值=======
Func<string,int> action4=(value)=>{
   Console.WriteLine("有參有返回值的Lambda表達式{0}",value);
    return 666;
};
int a=action4("hhh");

閉包:

內(nèi)層函數(shù)可以引用包含在它外層函數(shù)的變量,即便外層函數(shù)的執(zhí)行已經(jīng)終止。

注意:該變量的值并非創(chuàng)建變量時候的初始值,而是在外層函數(shù)處理過的最終值。

//例如
static Func<int,int>TestFun(int i)
{
    return delegate(int v)
    {
        //內(nèi)部函數(shù)占用著外部函數(shù)的i
        return i*v;
    }
}
//該變量的值并非創(chuàng)建變量時候的初始值,而是在外層函數(shù)處理過的最終值。
class Test
{
    public event Action action;
    public Test()
    {
        int value=66;
        action=()=>
        {
          Console.WriteLine("占用外部的value");  
        };
        //再次給事件中添加匿名函數(shù)
        for(int i=0;i<10;i++)
        {
            action+=()=>{
                //此時所有的i
                //為外部函數(shù)執(zhí)行完循環(huán)之后的最終值
                //最終值i=10;
                Console.WriteLine(i);
            };
        }
        //此時action中共有個匿名函數(shù)
        //第一個函數(shù)中value=66
        //其余for循環(huán)添加的匿名函數(shù)參數(shù)i的值均為10
        
        //對比:
        //再次給事件中添加匿名函數(shù)
        for(int i=0;i<10;i++)
        {
            int index=i;
            action+=()=>{
                //此時所有的i
                //為外部函數(shù)執(zhí)行完循環(huán)之后的最終值
                //最終值i=10;
                Console.WriteLine(index);
            };
        }
          //第一個函數(shù)中value=66
          //中間的for循環(huán)添加的匿名函數(shù)參數(shù)i的值均為10
          //最后的for循環(huán)添加的匿名函數(shù)參數(shù)index的值則是0~9
          //因為添加的是index臨時變量,index的數(shù)值就是自身最終數(shù)值 而i還在for
          //循環(huán)中自增
    }
}

List排序

//List排序
List<int> list=new List();
list.Add(8);
list.Add(3);
list.Add(2);
list.Add(5);
list.Add(1);
list.Add(6);
list.Add(4);
list.Add(9);
list.Add(7);
//1 List自帶的排序
list.Sort();
//ArrayList中也有Sort排序! 但是object類如何排序? 拆箱比較?
//自定義類排序
//若想使用排序函數(shù) 要實現(xiàn)一個排序接口
class Item:IComparable<Item>
{
    public int money;
    public Item(int money)
    {
        this.money=money;
    }
    //排序規(guī)則函數(shù)
    //List.Sort()根據(jù)存儲元素的方法來做排序
    public int CompareTo(Item other)
    {
        //返回值>0往后排
        //返回值=0保持不變
        //返回值<0往前移
        if(this.money>other.money)
        {
            return 1;//this對象移動到other對象后面
        }else
        {
            return -1;//this對象移到other對象前面
        }
    }
}
List<Item> itemList=new List<Item>();
itemList.Add(new Item(55));
itemList.Add(new Item(98));
itemList.Add(new Item(35));
itemList.Add(new Item(72));
itemList.Add(new Item(89));
itemList.Sort();//自定義排序規(guī)則調(diào)用排序
//小理解:List類在調(diào)用Sort排序時候,會將元素類型 as為排序接口類型(里氏替換原則)
//然后調(diào)用其CompareTo方法進行比較。

//3 通過委托函數(shù)進行排序
class ShopItem
{
    public int id;
    public ShopItem(int id)
    {
        this.id=id;
    }
}
List<ShopItem> shopItems=new List<ShopItem>();
shopItems.Add(new ShopItem(2));
shopItems.Add(new ShopItem(1));
shopItems.Add(new ShopItem(6));
shopItems.Add(new ShopItem(5));
shopItems.Add(new ShopItem(3));
shopItems.Add(new ShopItem(4));

//傳入中的對象為
//列表中的兩個元素 在比較時候會傳入元素做比較
static int SortShopItem(ShopItem a,ShopItem b)
{
    if(a.id>b.id)
    {
        return 1;
    }else
    {
        return -1;
    }
}
//調(diào)用Sort排序
//使用Sort的帶有委托參數(shù)的重載函數(shù)
shopItems.Sort(SortShopItem);
//使用匿名內(nèi)部類
shopItems.Sort(delegate (ShopItem a,ShopItem b)
{
     if(a.id>b.id)
    {
        return 1;
    }else
    {
        return -1;
    }
 });
//也可以使用Lambda表達式 
shopItems.Sort((a,b)=>
 {
     return a.id>b.id?1:-1;
 });
//遍歷結(jié)果
for(int i=0;i<shopItems.Count;i++)
{
    Console.WriteLine(shopItems[i].id);
}

協(xié)變和逆變

協(xié)變:和諧的變化。例如,里氏替換原則,父類可以裝子類,因此子類變父類是一種和諧的變化。string變成object(裝箱)也是協(xié)變。(可以理解小變大,順應(yīng)形勢,理所應(yīng)當(dāng)。)

逆變:于協(xié)變相反,逆常規(guī)的變化,不正常的變化,子類裝父類,object變string就屬于協(xié)變。(可以理解大變小,強制轉(zhuǎn)換,扭扭捏捏)

協(xié)變和逆變是用來修飾泛型的,只有在泛型接口和泛型委托中修飾泛型字符。

關(guān)鍵字:

協(xié)變:out(順勢而為,順出)修飾的只能作為 返回值

逆變:in(逆流而上,逆進)修飾的只能作為 參數(shù)

//協(xié)變和逆變
//out修飾類型 作為返回值
delegate T TestFunOut<out T>();
//in修飾的泛型 只能作為參數(shù)
delegate void TestFunIn(in T)(T t);

結(jié)合里氏替換原則:

class Father
{
    
}
class Son:Father
{
    
}
class Program
{
    static void Main(string[] args)
    {
        TestFunOut<Son> os=()=>{
            return new Son();
        };
        TestFunOut<Father> of=os;//父類型的委托裝載子類型的委托,二者都是委托的返回值
        //符合out 協(xié)變 如果沒有用out修飾,則說明二者是不同返回值類型的
        //委托,不可以進行賦值。
        TestFunIn<Father> InF=(value)=>
        {
            
        };
        TestFunIn<Son> InS=InF;
        Ins(new Son());
        //子類型的委托接受父類型的委托,但二者都是屬于委托參數(shù),可以理解為,
        //子類型的構(gòu)造函數(shù)調(diào)用父類型的構(gòu)造函數(shù)來構(gòu)造,底層本質(zhì)還是符合大裝小的原則
        //in修飾之后,才可以進行大小委托賦值。是一種逆變
    }
}

多線程

進程?

進程是運行中的程序,系統(tǒng)進行資源分配和調(diào)度的基本單位,是操作系統(tǒng)的基礎(chǔ)。

線程?

線程存在于進程中,是進程中的實際運作單位,是操作系統(tǒng)能夠進行運算調(diào)度的最小單位。一個進程中可以并發(fā)多個線程,他們共享利用進程中的堆棧資源。

多線程?

一個進程中除了必要的主線程之外,可以開啟其它的線程來完成一些計算處理。
一個進程中除了必要的主線程之外,可以開啟其它的線程來完成一些計算處理。

//線程
//聲明
Thread t=new Thread(MyThreadFun);
bool isRunning=true;
static void MyThreadFun()
{
    while(isRunning)
    {
         Thread.Sleep(10000);
         Console.WriteLine("新線程的執(zhí)行函數(shù)");
    }   
}
//啟動
t.Start();
//后臺線程
//設(shè)置為后臺線程之線程受主線程的影響(主線程結(jié)束,其它線程也結(jié)束),后臺線程不會防止應(yīng)用程序進程被終止
//如果不設(shè)置為后臺線程可能會導(dǎo)致進程無法正常關(guān)閉
t.IsBackground= true;

//關(guān)閉線程
//如果線程中有死循環(huán)一致執(zhí)行的,要關(guān)閉線程
//主動結(jié)束死循環(huán)
//對while()判斷條件控制設(shè)為false
isRunning=false;
//或者通過對線程提供的方法
//不一定都通用
t.Abort();
t=null;

//線程休眠
Thread.Sleep(10000);
//多線程--線程鎖
//避免對一個資源同時操作會造成邏輯錯誤
//多線程中要使用lock 保證一個內(nèi)存區(qū)一刻時間只能有一個線程訪問
Object obj=new Object();
//鎖的使用引用類型
lock(obj)
{
    //邏輯
}

預(yù)處理器指令

預(yù)處理是在源程序編譯成目標(biāo)指令之前,可以簡單的幫助選擇一些條件是否要編譯執(zhí)行。

常見的預(yù)處理指令:

#define Tony
#define Lili
#if Tony
   Console.WriteLine("Tony");
#elseif 
#endif Lili
   Console.WriteLine("Lili");
#else
    Console.WriteLine("其他人");
#undef Tony
    
#waring
#error 

反射和特性

反射:

程序正在運行時候,可以查看其它程序集或者自身的元數(shù)據(jù)。一個運行的程序查看本身或者其它程序的元數(shù)據(jù)的行為就叫反射。

我們知道,程序=數(shù)據(jù)+算法,程序在執(zhí)行過程中需要不斷地給它“投喂”數(shù)據(jù)養(yǎng)料,而反射就是獲取養(yǎng)料(類、函數(shù),變量等)的過程。有了反射,在運行時候可以動態(tài)的獲取自身所需要的資源,可以提高程序的拓展性和靈活性。

程序集:

程序集是經(jīng)由編譯器編譯得到的,供進一步編譯執(zhí)行的那個中間產(chǎn)物。在WINDOWS系統(tǒng)中,它一般表現(xiàn)為后綴為·dll(庫文件)或者是·exe(可執(zhí)行文件)的格式。

也就是說程序集是我們開發(fā)的項目中程序的集合,工程文件編譯運行所需要執(zhí)行的所有文件資源都算作程序集中的內(nèi)容。

元數(shù)據(jù):

元數(shù)據(jù)就是用來描述數(shù)據(jù)的數(shù)據(jù),例如在程序中,類、函數(shù)、變量等等信息就是程序的元數(shù)據(jù),她們保存在程序集中。

Type:

它是反射功能的基礎(chǔ),訪問元數(shù)據(jù)的主要方式.

Assembly

//Type
//獲取Type
//1 objet中的方法
int a=45;
Type type=a.GetType();
//2通過typeof獲取
Type type2=typeof(int);
//3通過類名字
//要說明類所在的命名空間
Type type3=Type.GetType("System.Int32");
//====三個訪問方式得到的Type類型相同

//得到類的程序集的信息 Assembly
Console.WriteLine(type.Assembly);
Console.WriteLine(type2.Assembly);
Console.WriteLine(type3.Assembly);

//===========================
class Test
{
    private int i=1;
    private int j=2;
    private string name;
    public Test(int i)
    {
        this.i=i;
    }
    public Test(int i,string str):this(i)
    {
        this.name=str;
    }
    public void Talk()
    {
        Console.WriteLine("123");
    }
}
//獲取類中所有的公共成員
Type type=typeof(Test);
MemeberInfo[] infos=type.GetMembers();
for (int i = 0; i < infos.Length; i++)
{
    Console.WriteLine(infos[i]);
}
//獲取所有的構(gòu)造函數(shù)
ConstructorInfo[] ctors=type.GetConstructors();
for(int i=0;i<ctors.Length;i++)
{
    Console.WriteLine(ctors[i]);
}
//獲取其中一個構(gòu)造函數(shù)并執(zhí)行
//獲取無參構(gòu)造函數(shù)
ConstructorInfo info=type.GetConstructor(new Type[0]);
//執(zhí)行無參構(gòu)造
Test obj=info.Invoke(null) as Test;//無參構(gòu)造 所以要傳null
//得到一個參數(shù)的有參構(gòu)造
ConstructorInfo info2=type.GetConstructor(new Type[]{typeof(int)});
obj = info2.Invoke(new object[]{5}) as Test;
//獲取兩個參數(shù)的構(gòu)造函數(shù)
ConstructorInfo info3=type.GetConstructor(new Type[]{typeof(int),typeof(string)});
obj = info2.Invoke(new object[]{5,"Tony"}) as Test;//與獲取的類型參數(shù)類型匹配

//獲取類的公共成員變量
FieldInfo[] fieldInfos=type.GetFields();
for (int i = 0; i < fieldInfos.Length; i++)
{
    Console.WriteLine(fieldInfos[i]);
}
//得到指定名稱的公共成員變量
//獲取J
FieldInfo infoJ=type.GetField("j");
Console.WriteLine(infoJ);
//通過反射獲取和設(shè)置對象的數(shù)值
Test test=new Test();
test.j=99;
test.name="Tony";
//通過反射獲取某個對象的數(shù)值
infoJ.GetValue(test);
//設(shè)置某個對象的數(shù)值
infoJ.SetValue(test,100);
//=================
//獲取類的公共成員方法
//以string類為例
Type strType=typeof(string);
MethodInfo[] methods=strType.GetMethods();
for(int i=0;i<methods.Length;i++)
{
    Console.WriteLine(methods[i]);
}
//如果存在方法重載 使用type數(shù)組來表示參數(shù)類型
MethodInfo subStr=strType.GetMethod("Substring",new Type[]{typeof(int),tyoeof(int)});
//調(diào)用獲取到的方法
string str="Hello,TonyChang";
object result=subStr.Invoke(str,new object[]{5,9});
Console.WriteLine(result);
//還可以通過
//GetEnumName GetEnumNames得枚舉

//得事件
//GetEvent
//GetEvents

//得接口
//GetInterface
//GetInterfaces

//得屬性
//GetProperty
//GetPropertys

//===============Activator=====
//可以使用它來快捷實例化Type類型得對象
Type testType=typeof(Test);
Test testObj=Activator.CreateInstance(testType) as Test;//無參構(gòu)造
testObj=Activator.CreateInstance(testType,99) as Test;//有參構(gòu)造
testObj=Activator.CreateInstance(testType,99,"Tony") as Test;//有參構(gòu)造(參數(shù)類型要對應(yīng))

//==============Assembly(程序集類)================
//主要用來加載其它程序集 加載之后用Type來使用其內(nèi)容
//可以加載dll文件等
//三種加載程序集的函數(shù)
//一般用來加載在同一文件下的其它程序集
Assembly asembly2 = Assembly.Load("程序集名稱");
//一般用來加載不在同一文件下的其它程序集
Assembly asembly = Assembly.LoadFrom("包含程序集清單的文件的名稱或路徑");
Assembly asembly3 = Assembly.LoadFile("要加載的文件的完全限定路徑");
//1.先加載一個指定程序集
Assembly asembly = Assembly.LoadFrom(@"C:\Users\MECHREVO\Desktop\CSharp");
Type[] types = asembly.GetTypes();
//遍歷打印   
for (int i = 0; i < types.Length; i++)
{
    Console.WriteLine(types[i]);
}           
//2.再加載程序集中的一個類對象 之后才能使用反射
Type icon = asembly.GetType("Lesson18_練習(xí)題.Icon");
MemberInfo[] members = icon.GetMembers();
for (int i = 0; i < members.Length; i++)
{
    Console.WriteLine(members[i]);
}           
//通過反射 實例化一個 icon對象
//首先得到枚舉Type 來得到可以傳入的參數(shù)
Type moveDir = asembly.GetType("Lesson18_練習(xí)題.E_MoveDir");
FieldInfo right = moveDir.GetField("Right");
           
//直接實例化對象
object iconObj = Activator.CreateInstance(icon, 10, 5, right.GetValue(null));
//得到對象中的方法 通過反射
MethodInfo move = icon.GetMethod("Move");
MethodInfo draw = icon.GetMethod("Draw");
MethodInfo clear = icon.GetMethod("Clear");
//進行調(diào)用程序
Console.Clear();
while(true)
{
    Thread.Sleep(1000);
    clear.Invoke(iconObj, null);
    move.Invoke(iconObj, null);
    draw.Invoke(iconObj, null);
}
//注:調(diào)用得程序是繪制方塊的練習(xí)題

特性

本質(zhì)是個類,可以對元數(shù)據(jù)的解釋和說明,供反射獲取的時候來獲取被調(diào)用的元數(shù)據(jù)的信息。

系統(tǒng)生成的特性:

過時特性:

迭代器

迭代器iterator

有時也稱為光標(biāo),是一種的軟件設(shè)計模式,迭代器模式提供一個方法順序訪問一個聚合對象中的各個元素,并且不暴露其內(nèi)部的標(biāo)識。

實現(xiàn)了迭代器的類才可以使用foreach遍歷。

//迭代器
//繼承兩個接口實現(xiàn)
//光標(biāo)移動
//迭代器
class MyList:IEnumerable,IEnumerator
{
    private int[] list;
    private int position = -1;
    public MyList()
    {
        list = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    }
    //實現(xiàn)IEnumerable的接口方法
    public IEnumerator GetEnumerator()
    {
        Reset();//返回之前要將索引器回到0
        return this;
    }
    //=========================
    public object Current
    {
        get => list[position];
    }
    //移動光標(biāo)
    public bool MoveNext()
    {
        ++position;
        return position < list.Length;
    }
    //重置光標(biāo) 
    public void Reset()
    {
        position = -1;
    }
}
//遍歷??!Main方法中
MyList list = new MyList();
foreach(int item in list)
{
    Console.WriteLine(item);
}

試著理解foreach的本質(zhì):

  1. 先獲取要遍歷對象的IEnumerator,調(diào)用其中的GetEnumerator方法獲取
  2. 執(zhí)行IEnumerator對象中的MoveNext方法
  3. 若返回為true,則繼續(xù)調(diào)用Current獲取得到值給item

使用語法糖實現(xiàn)迭代器

//迭代器
class MyList1:IEnumerable
{
    private int[] list;
    public MyList1()
    {
        list = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    }
    //實現(xiàn)IEnumerable的接口方法
    public IEnumerator GetEnumerator()
    {
       for(int i=0;i<list.Length;i++)
       {
            //使用語法糖
            //yield return 是C#提供給我們的語法糖
            //所謂語法糖,也稱糖衣語法
            //主要作用就是將復(fù)雜邏輯簡單化,可以增加程序的可讀性
            //從而減少程序代碼出錯的機會
            //要保留當(dāng)前狀態(tài),暫時返回出去
           yield return list[i];
           //其它兩個相關(guān)函數(shù)由系統(tǒng)自動生成
       }
    }
    //=========================
}
//遍歷!!Main方法中
MyList1 list1 = new MyList1();
foreach(int item in list1)
{
    Console.WriteLine(item);
}

使用語法糖為泛型數(shù)組實現(xiàn)迭代器文章來源地址http://www.zghlxwxcb.cn/news/detail-711509.html

//泛型實現(xiàn)迭代器類
class MyList<T> : IEnumerable
{
    private T[] array;

    public MyList(params T[] array)
    {
        this.array = array;
    }

    public IEnumerator GetEnumerator()
    {
        for (int i = 0; i < array.Length; i++)
        {
            yield return array[i];
        }
    }
}

到了這里,關(guān)于C#學(xué)習(xí)筆記--數(shù)據(jù)結(jié)構(gòu)、泛型、委托事件等進階知識點的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • C# 一個完整的委托、事件學(xué)習(xí)示例

    該示例符合委托、事件的定義規(guī)則,并且可以幫助大家更好地理解委托和事件的使用! 先定義了一個名為 MyEventArgs 的類,繼承自 EventArgs ,它包含一個 Message 屬性,用于存儲傳遞的消息。 Publisher 類中添加了一個 protected virtual 的方法 OnMyEvent ,用于觸發(fā) MyEvent 事件,并傳遞

    2024年02月07日
    瀏覽(25)
  • 【C#學(xué)習(xí)筆記】數(shù)據(jù)類中常用委托及接口——以List<T>為例

    【C#學(xué)習(xí)筆記】數(shù)據(jù)類中常用委托及接口——以List<T>為例

    ListT為什么是神?在談?wù)撨@個問題之前,我想先說說其他數(shù)據(jù)表結(jié)構(gòu)相較于ListT究竟差在了哪里…… 首先是 HashTable 本身呢就被 DictionaryTKey,TValue 完爆, HashTable 既不是線程安全的,也不是類型安全的,雖然提供了Synchronized()方法可以獲取線程安全的類型,以為自己是個哈希表就

    2024年02月11日
    瀏覽(20)
  • C#中內(nèi)置的泛型委托Func與Action

    從C# 3.0起很少需要自己聲明委托。 System.Func 是一個泛型委托,它可以表示帶有返回值的方法。它可以接受一個到多個輸入?yún)?shù),并返回一個指定類型的結(jié)果。 System.Func 委托的最后一個類型參數(shù)表示方法的返回值類型。而 System.Action 系列代表返回void的方法。 Func委托有很多種

    2024年02月05日
    瀏覽(23)
  • Kotlin筆記(五):泛型基礎(chǔ),委托

    ?Java自1.5版本引入了泛型的概念, Kotlin自然也支持泛型,Kotlin的泛型跟Java的泛型有相同之處,也有一些特別之處. ?在一般的編程模式下,我們需要給任何一個變量指定一個具體的類型,而泛型允許我們在不指定具體類型的情況下進行編程,這樣編寫出來的代碼將會擁有更好的

    2024年02月07日
    瀏覽(30)
  • c# 事件與委托

    //在C#中, 事件是一種特殊的委托 ,它允許對象通知其他對象發(fā)生了某個特定的事件。 //事件通常用于GUI應(yīng)用程序中,例如當(dāng)用戶單擊按鈕時,按鈕控件會引發(fā)Click事件, //然后其他對象可以訂閱該事件并執(zhí)行相應(yīng)的操作。 //以下是一個簡單的示例,演示如何在C#中使用事件和

    2024年02月06日
    瀏覽(25)
  • 委托與事件(一)——C#版本

    委托與事件(一)——C#版本

    ??委托是對 函數(shù)的封裝 ,可以當(dāng)作給方法的特征指定一個名稱。而事件則是 委托的一種特殊形式 ,當(dāng)發(fā)生有意義的事情時,事件對象處理通知過程。 ??委托是一種引用方法的類型。一旦為委托分配了方法,委托將與該方法具有 完全相同的行為 。 ??用例子來說明為

    2023年04月09日
    瀏覽(42)
  • C#委托和事件簡單復(fù)習(xí)

    太久沒用了,簡單的復(fù)習(xí)一下 快速過一遍語法使用 1.定義一個委托類型 只需要在聲明的前面加上delegate,其他的就跟聲明一個方法(函數(shù))類似 2.使用剛剛聲明的委托 需要定義一個返回值跟參數(shù)與我們剛剛定義的委托一致 3.然后聲明一個SayHello類型(委托)的變量 把

    2024年02月14日
    瀏覽(22)
  • 數(shù)據(jù)結(jié)構(gòu)-初識泛型

    數(shù)據(jù)結(jié)構(gòu)-初識泛型

    寫在前: 這一篇博客主要來初步的記錄以下泛型的相關(guān)內(nèi)容,內(nèi)容比較瑣碎,就不進行目錄的整合,后續(xù)可能會對泛型這里進行系統(tǒng)性的梳理,此篇博客主要是對泛型有一個簡單的認識與理解,需要知曉的內(nèi)容。 當(dāng)我調(diào)用func()的時候,進行傳遞的是一個真實的數(shù)據(jù),是一個

    2024年02月07日
    瀏覽(24)
  • 【數(shù)據(jù)結(jié)構(gòu)】泛型

    【數(shù)據(jù)結(jié)構(gòu)】泛型

    ? 作者:小胡_不糊涂 ?? 作者主頁:小胡_不糊涂的個人主頁 ?? 收錄專欄:淺談數(shù)據(jù)結(jié)構(gòu) ?? 持續(xù)更文,關(guān)注博主少走彎路,謝謝大家支持 ?? 在Java中,由于基本類型不是繼承自O(shè)bject,為了在泛型代碼中可以支持基本類型,Java給每個基本類型都對應(yīng)了 一個包裝類型。 基本

    2024年02月07日
    瀏覽(20)
  • 【數(shù)據(jù)結(jié)構(gòu)】初識泛型

    我們來看下面的代碼: 通過上面的代碼我們發(fā)現(xiàn),雖然在這種情況下,當(dāng)前數(shù)組任何數(shù)據(jù)都可以存放,但是,更多情況下,我們還是希望他只能夠持有一種數(shù)據(jù)類型。而不是同時持有這么多類型。 泛型語法: 我們可以把上面的代碼用泛型進行改寫: 代碼解釋: 類名后的 尖

    2024年02月07日
    瀏覽(21)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包