學習及工作中積累了一些零零碎碎的小筆記及技巧(C#),重溫和匯總一下。
1. 類別轉換時,如果你未能確定數值有效,使用TryParse 比 Parse 要更安全, TryParse 不會引發異常。
2. ?同??
1) 數據類型? 表示該類型變量可被賦為Null
例如: int 類型的默認值為0,int? 默認為 null
int i; //默認為0
int? i ; //默認為null
2) ?? 如果變量為null 時,默認的值
例如:
int j; int? i;
j= i ?? 10 ; //j 為 10
3. readonly 與 const 的使用
1) readonly 是運行時常量
2)const 是編譯時常量,它是 static的,因此不能 寫為 static const int constval=100;
3)const 效率相對高。
4. 數值類型 與 引用類型的 相等
1)對于數值類型,如果兩者的值相等,則返回 true
2)對於引用類型,如果指向同一個對象(地址)則返回 true;
3)對於 string 類型,則例外,它是判斷值相等。
5. using 是 try{…} finally{ xx.Dispose();} 的語法魔棒,最后會將對象自動 Dispose()
6. 大多數情況下 用 foreach 代替 for , 因為語法更簡單,以及自動帶 dispose. 但是 如果遍歷的過程中對自身變量進行增刪除操作時,則不能用 foreach.
7. 儘量使用泛型集合List 代替非泛型集合ArrayList,ArrayList的元素是 object ,存在 裝箱拆箱的性能損耗。
8. Linq 中的延遲求值和主動求值
例如:
List<int> list = new LIst<int>(){0,1,2,3,4,5,6,7};
//延遲求值
var temp1 = form c in list where c> 5
select c;
// 主動求值
var temp2 = (from c in list where c > 5
select c).ToList<int>();
list[0] = 11;// 改變 list 某個元素的值
//延遲求值
foreach (var item in temp1)
{
console.writeline(item.tostring()); //11,6,7
}
// 主動求值
foreach(var item in temp2)
{
console.writeline(item.tostring());//6,7
}
9. IEnumerable 與 IQueryable 的區別
1)IEnumerable 相對適合于 Linq to object,對本地集合進行查詢,排序等,可以用自定義主法。
2)IQueryable 相對適合于Linq to sql , 對遠端資料進行查詢等操作。不可以用自定義方法。
10. 委派
委派有兩個要點。第一委派是方法指針;第二委派是一個類。
例子:
delegate int AddHandler(int i,int j );
delegate int PrintHandler(string msg);
static void Main(stirng[] args)
{
AddHandler add = Add;
PrintHandler print = Print;
print(add(1,2).ToString());
}
static int Add(int i,int j)
{
return i+j;
}
static void Print(string msg)
{
console.writeline(msg);
}
注:上面的 委派定義 delegate 也可以直接用 Action,Fun 代替
static void Main(string[] args)
{
Func<int,int,int> add = Add; // 第一個 int 參數是返回的類型,后面接著是參數類型
Actoin<String> print =Print;//無返回值,直接帶參數類型
print(add(1,2).ToString());
}
另: 一個Action委派加 并行的例子
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ThreadSafeCollectionDemo
{
class Program
{
static void Main(string[] args)
{
ConcurrentBag<string> bag = new ConcurrentBag<string>();
Console.WriteLine($"当前包的元素个数【{bag.Count}】,是否为空【{bag.IsEmpty}】");
Task task1 = Task.Run(() =>
{
bag.Add("北洛");
bag.Add("云无月");
});
Task task2 = Task.Run(() =>
{
bag.Add("岑缨");
bag.Add("姬轩辕");
});
Task.WaitAll(task1, task2);
//包Bag支持添加重复的元素,和List一样都可以添加重复元素
bag.Add("岑缨");
Console.WriteLine($"当前包的元素个数【{bag.Count}】,是否为空【{bag.IsEmpty}】");
Action action = new Action(() =>
{
string element;
while (bag.TryTake(out element))
{
Console.WriteLine($"取出元素:【{element}】,当前线程编号:【{Thread.CurrentThread.ManagedThreadId}】");
}
});
//分成两部分取出
Parallel.Invoke(action, action);
string result;
if (bag.TryPeek(out result))
{
Console.WriteLine($"包存在元素:【{result}】");
}
else
{
Console.WriteLine("包当前没有元素");
}
Console.WriteLine($"当前包的元素个数【{bag.Count}】,是否为空【{bag.IsEmpty}】");
Console.ReadLine();
}
}
}
11.C# 的virtual虛函數
1)定義:在基類中聲明virtural并在一個或多個子類中被重新定義的成員函數(override重寫)。
2)作用:實現類的多態性。
3)VIRTUAL虛函數與普通函數的區別:
普通函數在編譯時就靜態地編譯到執行文件中,其相對地址在程序運行期間不會發生變化。
虛函數在編譯期間不被靜態編譯,它的相對地址是不確定的,它會根據運行期對象實例去判斷要調用的函數,其中聲明時定義的類叫做聲明類,執行時實例化的類叫實例類。
4)使用
A. 當調用一個對象的函數時,系統先直接去檢查對象的聲明類,查看調用的函數時否為虛函數;
B. 如果不是虛函數,直接運行該函數;如果是虛函數,就去檢查實例類,檢查是否有重新實現(重寫OVERRIDE),如果有,馬上執行該重新實現的函數;如果沒有,則往上找父類,直到找到第一個重載該函數的父類的函數。
例子:
class program
{
class A
{
public A()
{
print();
}
public virtual void print(){}
}
class B:A
{
int x=1;int y;
public B() {y=-1;}
public override void print()
{
Console.WriteLine("x={0},y={1}",x,y);
}
}
static void Main()
{
new B(); //輸出 x=1,y=0; 原因:創建子類時,會銜調用 父類的構造函數,然後再調用 子類的構造函數
}
}
重寫(Override)與重載(OverLoad)的區別
1)重寫(override): 子類重寫基類(父類)的方法。被重寫的方法必須是VIRTUAL虛方法,特點是3個相同:相同的方法名,相同的參數,相同的返回類別
2)重載overload:同一個類中多個方法名稱相同,3 個特點:名稱 相同;參數和列表 不同,返回值類型可以不相同
建議使用PLINQ 代替 LINQ
傳統LINQ是間線程的,PLINQ則是并發多線程的。
例如:
傳統LINQ,單線程,輸出有次序:
List<int> list = new List<int>(){0,1,2,3,4,5,6,7,8,9};
var query = form t in list select t;
foreach (var item in query)
{
Console.WriteLine(item.ToStirng());//傳統LINQ,單線程,輸出有次序
}
PLINQ ,并發多線程,注意線程安全和輸出無次序
var query = from t in list.AsParallel() select t;
foreach(var item in query)
{
Console.WriteLine(item.ToStirng()); //輸出無次序
}
//如果要按次序,則可以使用:
var query = from t in list.AsParallel().AsOrdered() select t;
14. 使用 Parallel簡化使用 Task
Parallel在 system.Threading.Task中有3個方法
1)prarllel.For : 適用于數組
int[] nums = {1,2,3,4};
Parallel.For(0,nums.length,(i) =>{
Console.WriteLine(nums[i].ToString()); //注:不一定按次序輸出
});
2) Parallel.ForEach : 適用于泛型集合
var list = New List<int>(){ 1,2,3,4,5};
Parallel.ForEach(list,(item)=>
{
Console.WriteLine(item.ToString()); //注:不一定按次序輸出
});
3) Parallel.Invoke(()=>{ //隱式啟動輒 兩個 tasks.
Console.WriteLine("task 1");
},
()=>{
Console.WriteLine("task 2");
});
15. 鎖 (LOCK)會讓多線程變成單線程,因為同時只允許一個線程訪問資源。
16. 用 params 減少函數的參數,例如:
void method(string,params int[] i);
未完(2022-04-25)