学习C#一年来的笔记,不对的地方欢迎指出,请多指教!!!
数据类型:大致分为值类型和引用类型(区别在于传递方式不一样)
1.值类型有
整数,bool struct char 小数
2.引用类型有
string 数组 自定义的类,内置的类
存储结构:值类型放在栈中,引用类型的引用(数据地址)放在栈中,数据放在堆中
数据赋值:值类型是值传递(直接改变值) 引用类型则进行引用传递(改变堆中的内存地址)
数组结构:如果数组是一个用于存储值类型的数组,那么堆中的数据存储的就是值类型,如果是用于存储引用类型的数据,那么堆中的数据存放的还是引用(内存地址)
var 匿名类型(这个变量在开始时类型是不确定的,当它被赋值后类型就不能改变了)//它的类型可以是我们我们自己定义的类型
sbyte 8位有符号整数
short 16位有符号整数
int 32位有符号整数
long 64位有符号整数
byte 8位无符号整数
ushort 16位无符号整数
unit 32位无符号整数
输入:
a=b.Parse(Console.Readline())
a是输入对象(已经声明),b是该对象的类型。
获取当前的系统时间:
DateTime 变量 = DateTime.now;
常量声明就赋值,变量声明可不赋。
变量名不能以数字开头;
不能有符号、空格和关键字
使用Convert类下的方法进行基本类型的转换。
例如:
object Ff = 11;
int i = Convert .ToInt16 (Ff);
等效于
object Ff = 11;
int i =(int)Ff;
在使用方法时,可以调用任何位置的静态方法,属性,不能使用动态的方法,属性
对象必须进行声明后再初始化才能进行使用例如:
————————————————————字符串与可变字符串:
String的对象是不可改变的,每次改变字符串都需要生成新的字符串并分配内存,而String
Builder的对象是可改变的,不需要生成新的字符串,使用StringBuilder对象可以提升性能
多用于在字符串后添加大量对象。
String类:
替换字符串里的字符或字符串:
a=b.Replace("旧","新") 字符串
a=b.Replace('旧','新') 字符
a是新字符串,b是旧字符串
比较字符串是否相同:
String.Compare(a,b)等效于a.CompareTo(b) 返回值是int 相同为0 大1 小-1
String.Equals(a,b)等效于a.Equals(b) 返回值是bool 相同为ture 否False
a=b.Contains(c); 在字符串b中查找是否存在字符串c 返回值是布尔值a。
拼接字符串:
DateTime b string a
a=String.Format("{0}{1}{2}形式符号随意",k,c,d)
a=String.Format("{0:D}",b) 可以格式化日期
截取字符串:
string a=b.Substring(c,d)
a是截取段
b是已知字符串(目标)
c是截取位置减1
d是截取的字符个数(换行是一个字符)
分割字符串:
a=b.Split(c)
a是新字符串数组,b是待分割字符串,c是分割符字符数组
插入字符串:
a=b.Insert(c,d)
a是得到的新字符串,b是被插入字符串,c是插入位置减1,d是插入字符串
在字符串的左右侧添加字符:
a=b.Padleft或者b.PadRight (c,d )
a是得到的新字符串,b是被添加字符串,c是新字符串的字节,d是被添加的字符
(多出的字节都用c添加)
删除字符串:
a=b.Remove(c,d)
a是新得到的字符串,b是被删除字符串,c是删除位置减1,d是删除字节个数
(可以不要参数d,将删除c以后的所有字符)
StringBuilder类:
添加字符串至StringBuilde对象的末尾:
a.Append(b)
a是StringBuilder对象,b是字符串
将自定义的格式变量添加到StringBuilder对象的末尾:
a.AppendFormat("{0}{1}格式随意",b,c)
a是StringBuilder对象,b,c是字符串
将字符串添加到StringBuilder对象中:
a.Insert(b,c)
a是StringBuilder对象,b是添加位置减1,c是添加的字符串
删除StringBuilder对象里的字节:
a.Remove(b,c)
a是StringBuilder对象,b是删除开始位置,c是删除字节个数
修改StringBuilder对象里的指定字符:
a.Replace(b,c)
a是StringBuilder对象,b是旧的字符串,c是新的字符串
————————————————————————————流程控制语句
选择语句:
if...else:
if(a)
{
a
}
else if ()
{
}
else
{
}
a是布尔表达式,如果a为真则执行b,否则跳过
switch:
switch(a)
case b :x ;
break;
case c :y ;
break;
case d :z ;
break;
。。。。。。
a是常量表达式,b,c,d是常量,x,y,z是语句块。
(布尔表达式)? (a):(b)
判断布尔表达式,为真返回值a,为假返回值b。
迭代语句:
while和do...while:
while(a) do
{ {
语句块; 语句块;
break; break;
语句块; 语句块;
continue; continue;
} }
a是布尔表达式,break将直接跳出循环,continue将进入下一次循环
foreach:
枚举一个类型的数据,并对这些数据执行一次嵌入语句
ArrayList a=new ArrayList() //声明枚举变量
alt.Add(b) //在枚举变量中添加值
alt.Add(c)
alt.Add(d)
foreach(bcd的类型 n in a)
{
嵌入语句;
}
a是枚举变量,b,c,d是a的值,n是执行变量的临时名字。
跳转语句:
break:用于终止(直接跳出)循环和比较,只作用于最里层的循环或比较(switch,while,do...while,for,foreach)。
continue:用于重新进行一次比较或者循环用于(while,do...while,for,foreach)只作用于最里层的循环或比较。
noto:用于跳转到 noto标签处。
return:用于定义方法时返回数值。
——————————————————————————————————数组与集合(int 的常用排序方法)
获取二维数组的行数 a.Rank 获取二维数组的列数 a.GetupperBound(arr.Rank-1)+1
1.数组的声明:
a[] b =new a[c]
a是数组的类型,b是数组的名称,c是数组的长度。
2.数组的排序:
冒泡法:
// 冒泡法 (神奇:每次循环里交换时,都能交换到第i次循环里最小的数)
for (int i = 0; i < Hgj.Length;i++ )
{
for (int j = Hgj.Length-1; j>=1; j--)
{
if (Hgj[j] < Hgj[j - 1])
{
int temp = Hgj[j];
Hgj[j] = Hgj[j - 1];
Hgj[j - 1] = temp;
}
}
}
直接插入法:
/*for (int i = 0; i < Hgj.Length; i++)//插入排序法(在第i次循环的时候找到第i个数在该数以前排序中的位置,一直交换中使数组有后移变化)
{
int j=i, temp;
temp = Hgj[i];
while ((j > 0) && (Hgj[j - 1] > temp))// while 判断+循环的妙用
{
Hgj[j] = Hgj[j - 1];
j--;
}
Hgj[j] = temp;
}*/
选择排序法:
/*int j, temp; //选择排序法 算法思想:找到第i个数以后比i小的数,然后交换,角标不变 (无角标)
for (int i = 0; i <Hgj.Length ; i++)
{
for (j = i + 1; j<Hgj.Length; j++)
{
if (Hgj[i] < Hgj[j])
{
continue ;
}
else
{
temp = Hgj[i];
Hgj[i] = Hgj[j];
Hgj[j] = temp;
}
}
}*/
自创角标控制:
选择排序法 (有角标 )/* for (int i = 0; i < Hgj.Length-1; i++) //
{
int min = i;
for (int j = i+1; j < Hgj.Length ; j++)
{
if (Hgj[min] > Hgj[j])
{
min = j;
}
}
int temp = Hgj[i];
Hgj[i] = Hgj[min];
Hgj[min] = temp;
} */
快速排序法:
算法:以数组的第一个值为基准值,用数组前面和后面的数值交叉(每一次交叉都为下一次交叉提供了位置)和基准值进行比较然后改变位置,使得比基准值大的元素排在基准值以后反之亦然,然后用递归实现多次切割
代码:
class Sort
{
public int Hjk(int[] a, int left, int right)//快速排序法的核心:取得基准值所在的位置
{
int i = left;
int j = right;
int jzh=a[left];
int temp;
while (true)//循环中一定不能覆盖,必须交换
{ if (a[j] > jzh&&i<j)
{
j--;
}
else if (a[j] < jzh && i < j)
{
temp = a[i];
a[i] = a[j];
a[j] = temp;
i++;
}
else if (a[i] < jzh && i < j)
{
i++;
}
else if (a[i] > jzh && i < j)
{
temp = a[j];
a[j] = a[i];
a[i] = temp;
j--;
}
else if (i == j)
{
a[i] = jzh;
break;
}
}
return i;
}
public void Paixu(int[] a,int left,int right)//递归实现排序
{
if(left<right)//递归结束条件是left=right
{
int i = Hjk(a,left,right);
Paixu(a, left, i - 1);
Paixu(a, i + 1, right);
}
}
}
直接方法排序:
从小到大: Array.Srot(a); (a是一维数组)
反向排序: Array.Reverse(a); (a是一维数组)
3.数组的合并与拆分
数组的合并:
将两个一维数组合并为一个一维数组: 使用for嵌套if 合并
将两个一维数组合并为一个二维数组: 使用for嵌套switch 合并
拆分一个道理。
集合(指的是没有类型的列表(List)):
ArrayList ad = new ArrayList() ;
ad.Add('a');//字符
ad.Add("asd");//字符串
ad.Add(1);//整型
ad.Add(true);//布尔型
foreach(object a in ad)//遍历输出
{
Console.WriteLine(a);
}
也可以使用固定类型的列表 声明构造方式: List<int> qe = new List<int>() { 2,5,8,9};//对列表进行赋值 或者 var qe = new List<int>();
常用方法:
Capacity 获取和设置集合中可包含的元素数
Count 获取集合中的元素个数
IsFixedSize 获取一个值显示集合是否具有固定大小
IsReadOnly 获取一个值显示集合是否只读
IsSynchronized 获取一个值显示是否同步对集合的访问
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Item 获取或显示集合中索引处的元素 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
集合的声明:
ArrayList a = new ArrayList() (声明一个不限元素个数的集合对象a) // 使用vs编程 需要添加 System.Collections 命名空间
ArrayList a = new ArrayList[b] (声明一个有b个元素的集合对象a)
ArrayList a = new ArrayList[c] (声明一个包含了数组c的集合对象)
集合元素的添加:
a.Add(b) (将元素c添加到集合a的末尾)
a.insert(b,c) (在索引为b的位置插入元素c)
集合元素的移除:
a.Clear(); (清除集合a内的所有元素)
a.Remove(c) (清除集合a内所有与c匹配的元素)
a.RemoveAt(b) (清除集合a内索引为b位置的元素)
a.RemoveRange(b,c) (清除集合a内从索引值b开始的c个元素)
集合元素的查找:
a.Contains(b) (查找集合a内是否存在元素b(返回值是布尔变量))
a.IndexOf(b,c,d) (查找集合a内元素b在c位置以后d个元素中b的位置) c,d可省略 c的默认值是0,d的默认值是总集合元素减c
a.LastIndexOf(b,c,d) (查找集合b内最后一个元素b在c位置以后d个元素中的位置)
哈希表:
————————————————————————————异常处理(编写弹性代码)
语句格式:
try//程序顺序执行try块里的代码,当遇到第一个异常时,就不会继续
{
}
catch(<exception type> e)//当try块里的代码遇到异常类型e时执行catch块里的代码,可以不写括号里的异常类型,只要出现异常就会执行catch块里的代码
{
}
finally//最后都会执行的代码
{
}
(一个异常调试结构里必须有try块,catch和finally块必须有一个,其中catch块可以有多个)
弹性代码(健壮代码的编写结构):
可以使用以下结构来编写弹性代码,不至于程序出现异常就崩溃
while(true)
{
try
{
<执行代码>
break;
}
catch()
{
<提示信息>
}
}
——————————————————————————————结构:
结构是一种值类型,向方法传递结构时是通过值类型传递而不是通过引用传递。结构是不能继承的,定义属性时不能初始化实例字段(在类中,必须初始化实例字段)。
结构的申明:
结构修饰符+struct+结构名称
结构内属性的声明:
public(属性修饰符)+属性类型+属性名称; (结构的属性时无法赋予初始值)
结构内方法的声明:
public(方法修饰符)+返回值类型+方法名
{
}
实例:
public Rect
{
public double wight;
public double height;
public Rect(double x,double) // 用于初始化矩形的长和宽 十分重要 没有返回值类型和不需要返回值 (构造函数)
{
wight=x;
height=y;
}
public double Area(wight,height)// 用于计算矩形的面积 十分重要 必须有返回值类型和具有返回值 y
{
return wight*height;
}
}
声明+初始化方法:
Rect abc =new Rect(a,b) // 十分重要 实例化矩阵abc并初始化它的长和宽
——————————————————————————————类:
类是一种数据结构,它可以包含数据成员(常量和域(字段)),函数成员(方法,属性,事件,引索器,运算符,构造函数,解析函数)和嵌套类型 (类支持继承)
类的声明:
(类修饰符)+class+ (类名)
类修饰符:
new:仅在嵌套声明类型中使用,表明类中隐藏了由基类继承而来的、与基类中同名的成员。
public:不限制对该类的访问。(可以在其他项目中使用(通过添加引用的方法))
protected:只能在其所在类和所在类的派生类中进行访问。
internal:只能在其所在类进行访问。
private:只能在.NET中的应用程序或库才能访问。
abstract:抽象类(不允许建立类的实例)
sealed:密封类不允许被继承
类的使用:
我们自己定义的类,必须声明过后进行初始化才能使用 (声明+初始化方法: Type a=new Tpye() )
———————————————————————————————属性:
属性是一种关于类或者方法的特定的对象。
编程规范里一般将属性的访问级别定位为 private 使用 set和get方法来设置它的输入输出(访问器的数据一定要一致)
实例:
public class D
{
public double wight=0;//这里只是定义了一个用于属性Wight 的字段
private double height;
public double Wight//定义一个类D的属性,设置该属性的输入输出数据 (标准写法如下)
{
get//输出
{
return wight;
}
set//输入
{
wight = value;
}
}
public double Wight{get;set;}(简写格式)(不用我们自己去定义一个wight字段,编译器自动给我们提供了一个影藏的字段)
//public D(double x, double y)//该函数就是构造函数如果不进行注释的话,就不能在main函数中使用 new 方法进行类的出初始化
//{
// wight = x;
// height = y;
//}
public double Area()
{
return wight * height;
}
}
属性区别于字段的三大好处:
一、属性可以使用set方法来控制属性的参数校验(控制用户的输入范围)
二、属性内可以在 set 和 get 方法前加上private来控制属性的适用范围(加上private 的方法块只能在类的内部调用)
三、属性可以通过写或者不写set和get(可以只写其一,如果都不写那和字段有什么区别)来控制该属性在main函数中的可读可写状态
————————————————————————————————————————方法:
声明格式: 访问级别修饰符+ 类型 +方法名(参数){方法体}
继承:
用法:
c#语言不支持多重继承(只可以继承于一个父类),但是支持多接口继承,继承自父类的子类里有父类的所有数据成员以及函数成员;可以使用父类去声明一个变量然后用子类去构造(实例化/初始化)
;但是使用前要进行强制类型转化(在变量前加一个(<father tpye>))
特殊方法:
虚方法:在父类里声明方法时在访问修饰符后加一个virtual例如 public virtual double Area() 在子类中可以重新修改该方法 在访问修饰符后加override 例如 public override double Area()
在使用父类对象的时候使用父类方法,使用子类对象的时候调用修改后的方法 (使用虚方法的时候,父类里的方法已经被修改,子类对象无法调用)
隐藏方法: 在子类中重新定义父类已经有的方法(方法的签名一致) 这样将会隐藏父类中的方法,(只是隐藏,父类方法是存在的,子类对象是可以使用的)(用什么类声明的对象就会使用什么类里的方法)
抽象方法: 在父类中定义一个抽象方法(在访问修饰符的后面加一个abstract,此时父类必须定义成一个抽象的类),此时父类(抽象基类)是不完整的不能使用父类去实例化,可以拿父类去声明,拿子类去构造,在子类中必须重写抽象方法
密封方法和密封类:任何一个重写的方法都可以设为密封方法(在方法前加一个sealed)表示该方法不能被重写,在声明了类的时候可以讲类声明为一个密封类表示这个类不能被继承
派生类的构造方法:在子类中写构造方法的时候,在构造方法后加 :(父类构造方法) 表示调用父类的构造方法 (父类的构造方法先于子类构造方法使用)
静态方法和静态类:静态(使用static进行修饰的成员,包括静态方法和静态属性,他们只能通过类名来进行访问,静态的成员是不能通过构造函数进行构造的)
————————————————————————————————————————接口(interface):
接口是可以彼此继承的(继承方式和类的完全一样)
public interface A
{
void Method1();// 这里不能有{},因为这是方法的实现,在接口内不能有任何成员的实现方式
}
public interface B:A //接口B继承于接口A(和类的继承方式完全一样)
{
void Method2();
}
——————————————————————————————————————————泛型:
例如:
泛型类:
class ClassA <T>
{
private T a;
private T b;
public ClassA(T a, T b)
{
this.a = a;
this.b = b;
}
public String Getsum()
{
return a +" "+ b;
}
}
声明构造: var a =new ClassA<int>(45,56)
泛型方法:
定义一个抽象化(为定义方法类型)的方法,在使用方法的时候才定义方法的类型,可以让一个方法在不同类型的参数中灵活使用
实例:
public static string Getsom<T>(T a, T b)
{
return a + " " + b;
}
Console.WriteLine(Getsom<double>(12.3, 5.6));
Console.ReadLine();
————————————————————————————关于正则表达式:
常用方法: Regex.IsMatch(返回一个bool 类型,用于判断字符串里的书写规则是否与正则表达式字符串一致)
方法重载:
IsMatch(string input, string pattern);//input:目标字符串,pattern正则表达式字符串,option枚举按位组合,matchTimeout超时间隔
没学 IsMatch(string input, string pattern, RegexOptions options);\\option 是一个枚举类型正则表达式设定
没学 IsMatch(string input, string pattern, RegexOptions options, TimeSpan matchTimeout);
(非静态) Regex.Replace(返回值是一个已经修改过的字符串)
方法重载:
Replace(string input,string pattern,string replacement) //input:目标字符串,pattern正则表达式字符串
Replace(string input,string pattern,string replacement,RegexOptions options) //option 是一个枚举类型正则表达式设定
正则表达式是字符串的书写规则 //比如 option= RegexOptions.In
列如: //可以用于忽略字母大小写
@"^\d*$" :代表一个只包含数字的字符串。
@"^\w*$" : 表示一个只有字母数字和_符号的字符串
@"\d" ; 表示一个包含数字的字符串
@"[^ahor]"; 表示除了ahor这几个字符为外的所有字符
@"[asd]" : 表示asd里面的任意一个字符
@"[a-h]" : 表示在字母表里面a-h的所有字符(一个)
@"[^\d{5,12}$]":表示5—12个数字字符
@"^((25[0-5])|(2[0-4]\d)|([0-1]?\d?\d))\.$" :表示一个0-255之间数字(其中三个类别是250-255,200-249,0-199)加上.
常用元字符:
字符 说明
\w 匹配字母、数字、下划线、汉字 (指大小写字母、0-9的数字、下划线_)
\W \w的补集 ( 除“大小写字母、0-9的数字、下划线_”之外)
\d 匹配数字 (0-9数字)
\D 表示\d的补集 (除0-9数字之外)
^ 匹配必须出现在字符串的开头或行的开头
$ 匹配必须出现在以下位置:字符串结尾、字符串结尾处的 \n 之前或行的结尾。
{n} 匹配前面的字符n次
{n,} 匹配前面的字符n次或多于n次
{n,m} 匹配前面的字符n到m次
? 重复零次或一次
+ 重复一次或更多次
* 重复零次或更多次
IP4的地址正则表达式是:
@"((((25[0-5])|(2[0-4]\d)|([0-1]?\d?\d))\.){3}(25[0-5])|(2[0-4]\d)|([0-1]?\d?\d))"
——————————————————————委托:
委托可以指向多个方法,这样的委托叫做多播委托,如 Func a=Method1; a+=Method2 可以使用委托的GetInvocationList()方法来提取委托里面的每一个方法,返回值是一个delegate 数组,可以使用 DynamicInvoke()方法来进行delegate数组元素的方法使用
系统预制的委托类型:
action: 没有返回值的委托 可以在声明的时候在action后面加上<T> ,T为泛型类型 来说明声明的这个action委托是有参数的;
func: 有返回值的委托类型 在声明委托的时候在fuc后面加上<T><T><B>,T为泛型类型,说明这个委托的参数类型,B也是泛型类型,用于说明委托的返回值类型。
例如:
普适性的快速排序法法:
static public void Common_sort<T>(T[] chart,Func<T,T,bool> compare_method)
{
for (int i = 0; i < chart.Length; i++)
{
for (int j = i + 1; j < chart.Length; j++)
{
if (compare_method(chart[i], chart[j]))
{
continue;
}
else
{
T temp = chart[i];
chart[i] = chart[j];
chart[j] = temp;
}
}
}
}
里面的compare_mathod方法需要在自定义的类里写出来:(这里的Employees类是我自己定义的一个拥有Name,和Salary属性的类型)
如
static public bool employees_compare(Employees e1,Employees e2)
{
if (e1.Salary<e2.Salary)
return true;
else
return false;
}
匿名方法:
常用的声明委托的方法是使用声明匿名方法的格式:(简化了委托指向的方法的声明)
匿名方法就是没有方法名的方法,
列如:
Func<int, int, int> sdfg = delegate(int a, int b)
{
return a + b;
};
lambda表达式:
自c# 3.0 以后,出现了lambda表达式 来代替了匿名方法的使用(简化了匿名方法)
lambda表达式的格式如下:
Func<int, int, int> asdf = (a, b) => //相比匿名方法,lambda表达式不用在声明委托的时候再一次的去重复声明方法中变量的类型,
{
a = a * a;
return a + b;
};
当Func<>里面的所用到的参数只有一个时,不用去写括号,当方法体里的语句只有一句时,不用去写大括号
Func<int, int,int> asdf = (a,b) => a * b;
事件:
事件是一种特殊的委托,区别于委托的用法是强制规定了委托不能在定义委托的类外面调用;
用处:给定义委托的这个类(被观察者)一个能发布某个方法已经执行的消息,在别的类里进行订阅的功能
发布/订阅机制的原理: // 观察者在声明的时候就将目标确定了只要被观察者执行Method2并且条件符合时机,观察者就会执行Method1
观察者类的声明 构造函数 观察者(属性1,属性2,被观察者 a) 自身方法 Method1()
{ {
……//属性定义 ……
a.event1+=Method1;//订阅消息
}
}
被观察者的声明 构造函数 被观察者(属性1,属性2) 自身方法 Method2() 事件声明 public event Action event1;
{ {
…… ……
} if(时机的判断)
event1(); //消息的发布
}
————————————————————————————————————LINQ语句
定义:集合实现筛选功能的类和方法
PersonList是我自己定义的一个类的实例,这个类里有属性如下:
public int Id { get; set; }
public string Name { get; set; }
public int Age{get;set;}
public string Menpai { set; get; }
public string Kongfu { set; get; }
public int Level{get;set;}
KongList也是我自己定义的一个类的实例,类的属性如下:
public int KongfuId { set; get; }
public string KongfuName { set; get; }
public int Lethality { set; get; }
数组的声明和构造:
MartialExpert[] PersonList = new MartialExpert[]
{new MartialExpert(){ Id = 1, Name = "黄蓉", Age = 18, Menpai = "丐帮", Kongfu = "打狗棒法", Level = 9 },
new MartialExpert(){ Id = 2, Name = "洪七公", Age = 70, Menpai = "丐帮", Kongfu = "打狗棒法", Level = 10 },
new MartialExpert(){ Id = 3, Name = "郭靖", Age = 22, Menpai = "丐帮", Kongfu = "降龙十八掌",Level = 10 },
new MartialExpert(){ Id = 4, Name = "任我行", Age = 50, Menpai = "明教", Kongfu = "葵花宝典", Level = 1 },
new MartialExpert(){ Id = 5, Name = "东方不败",Age = 35, Menpai = "明教", Kongfu = "葵花宝典", Level = 10 },
new MartialExpert(){ Id = 6, Name = "林平之", Age = 23, Menpai = "华山", Kongfu = "葵花宝典", Level = 7 },
new MartialExpert(){ Id = 7, Name = "岳不群", Age = 50, Menpai = "华山", Kongfu = "葵花宝典", Level = 8 },
new MartialExpert() { Id = 8, Name = "令狐冲", Age = 23, Menpai = "华山", Kongfu = "独孤九剑", Level = 10 },
new MartialExpert() { Id = 9, Name = "梅超风", Age = 23, Menpai = "桃花岛", Kongfu = "九阴真经", Level = 8 },
new MartialExpert() { Id =10, Name = "黄药师", Age = 56, Menpai = "梅花岛", Kongfu = "弹指神通", Level = 10 },
new MartialExpert() { Id = 11, Name = "风清扬", Age = 98, Menpai = "华山", Kongfu = "独孤九剑", Level = 10 }
};
Kongfu[] KongfuList = new Kongfu[]
{
new Kongfu(){KongfuId=1, KongfuName="打狗棒法", Lethality=90},
new Kongfu(){KongfuId=2, KongfuName="降龙十八掌", Lethality=95},
new Kongfu(){KongfuId=3, KongfuName="葵花宝典", Lethality=100},
new Kongfu() { KongfuId= 4, KongfuName = "独孤九剑", Lethality = 100 },
new Kongfu() { KongfuId = 5, KongfuName = "九阴真经", Lethality = 100 },
new Kongfu() { KongfuId = 6, KongfuName = "弹指神通", Lethality = 100 }
};
1.LinQ表达式写法…………………………………………………………………………………………………………在PersonList里面筛选书Level>=10的元素,返回值是一个数组List
//var List = from p in PersonList //from in 关键字: p用于代表PersonList里面的一个元素
// where p.Level >= 10 //where 关键字: 用于对p进行条件判断
// select p; //select 关键字: 用于放回p值,放入List中
2.类方法的写法……………………………………………………………………………………………………………在PersonList里面筛选出Level>=8的数据,返回值是一个数组List
//var List=PersonList.Where(Screen); //写法1
//var List = PersonList.Where(m=>m.Level>=8&&m.Kongfu=="独孤九剑"); //写法2(lambda表达式写法)
//public static bool Screen(MartialExpert temp)
//{
// if (temp.Level >= 8) return true;
// return false;
//}
3.LINQ语句的联合查询(最好理解)类似于SQL语句…………………………………………………………………在PersonList和KongfuList里进行联合查询筛选出元素中功夫名字一样并且威力大于90的元素
返回一个由名字,武学,威力组成的集合
//var List = from p in PersonList
// from k in KongfuList
// where p.Kongfu == k.KongfuName && k.Lethality > 90 //必须加上p.Kongfu==k.KongfuName 这样才能让记录一一对应
// select new {p.Name,k.KongfuName,k.Lethality }; //临时生成的对象语句 new { ... };
4.LINQ语句联合查询的扩展方法(最少代码)…………………………………………………………………………在PersonList和KongfuList里进行联合查询选出选出元素中武学一样的元素
并且返回一个集合到List
var List = PersonList.SelectMany(k => KongfuList/*和PersonList集合进行联合*/, (p, k) => new { p,k}/*这里返回一个由p,k组合而成的集合(一对多)*/)
.Where(t=>t.p.Kongfu==t.k.KongfuName);//在杂乱数据中筛选出有效数据,可以在这里添加一些筛选条件
5.join on 语句…………………………………………………………………………………………………………………联合查询
var List = from p in PersonList
join k in KongfuList on p.Kongfu equals k.KongfuName
where p.Id<5
select new { k, p };
6.多个集合进行先解分组 into 语句 (分组)…………………………………………………………………………………………………………把PersonList里的数据进行分组,已第一张表来分
var List = from k in KongfuList
join p in PersonList on k.KongfuName equals p.Kongfu
into gourps
select new { k.KongfuName,k.Lethality,renshu=gourps.Count() };
7.group by 语句(在一个集合里面进行分组,结果返回一个分组集合,每一个元素都是一个门派)
//var List = from p in PersonList
// group p by p.Menpai into L //对对象p进行p的Menpai属性的分组,并且把值赋到集合L里去
// select new {count=L.Count(),key=L.Key};
//foreach
//(var temp in List)
// {
// Console.WriteLine(temp);
// }
8.集合的all和any方法
bool res ;
//res=PersonList.Any(m=>m.Kongfu=="打狗棒法"); //集合的Any(Func)方法 这里使用了Func 委托的lambda表达式的写法 (在集合PersonList中,有没有至少一个元素的Kongfu属性是“打狗棒法”)
res = PersonList.All(m=>m.Kongfu=="打狗棒法"); //集合的All(Func)方法 这里使用了一个委托的lambda表达式的写法(在集合PersonList中,是不是所有元素的Kongfu属性都是“打狗棒法”)
——————————————————————————————————————————————对象的Tpye特性和反射
反射:程序在运行时,可以查看其它程序集或其本身的元数据。一个运行的程序查看本身的元数据或者其他程序集的元数据的行为叫做反射。(这些所谓的特性都是反射)
每一个对象都有一个Tpye对象,Type对象里储存着这个对象的类的成员信息(这个类的方法,字段,属性)
——————————————————————————————————————————————对象的Tpye特性和反射
反射:程序在运行时,可以查看其它程序集或其本身的元数据。一个运行的程序查看本身的元数据或者其他程序集的元数据的行为叫做反射。(这些所谓的特性都是反射)
每一个对象都有一个Tpye对象,Type对象里储存着这个对象的类的成员信息(这个类的方法,字段,属性)
Class1 class1 = new Class1();
Type type = class1.GetType();
string class1_name = type.Name;//获取对象的类名
class1_name += " 类名 ";
class1_name += type.Namespace;//获取对象的命名空间
class1_name += " 命名空间 ";
class1_name += type.Assembly;//获取对象的程序集 加载程序集
class1_name += " 程序集 ";
Console.WriteLine(class1_name);
FieldInfo[] asdf = type.GetFields(); // 获得类的公有字段 FieldInfo 是一个存储类的字段的类型,在命名空间System.Reflection下 该方法返回一个FieldInfo数组
foreach (var a in asdf)
{
Console.WriteLine(a+"***公有字段");
}
PropertyInfo[] qwer = type.GetProperties();//获得类的公有属性 PropertyInfo 是一个储存类的属性的类,在命名空间System.Reflection下 该方法返回一个PropertyInfo数组
foreach (var a in qwer)
{
Console.WriteLine(a+"***公有属性");
}
MethodInfo[] zxcv = type.GetMethods();//获得类的公有方法 MethodInfo 是一个储存类的属性的类,在命名空间System.Reflection下 该方法返回一个MethodInfo数组
foreach(var a in zxcv )
{
Console.WriteLine(a + "***公有方法");
}
————————————————————————————————————————————方法的Obsolete特性
可以使用方法的Obsolete 特性来对标志方法的弃用 (在编译器里对旧的方法上有中杠线)
[Obsolete("这个方法已经被弃用了,大哥啊")]
public static void OldMethod()
{
Console.WriteLine("旧的方法");
}
static void Main(string[] args)
{
OldMethod();
Console.WriteLine();
Console.ReadKey();
}
可以给Obsolete添加一些参数 字符串后面的布尔值表示找个方法是否停用
[Obsolete("这个方法已经被弃用了,大哥啊",true)] (这个表示停用)
————————————————————————————————————————————方法的Conditional 特性
可以使用这个特性进行方法的直接停用
在方法定义的头上加上一个[Conditional("Text1")] 表示对这个方法进行了监测 Text1 是一个宏编译器监测到这个宏的定义就会去调用方法,如果没用检测的这个宏的定义就不会去调用方法
该特性在命名空间 System.Diagnostics 下。
//#define Text1 // 宏定义Text1
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
namespace Conditional
{
class Program
{
[Conditional("Text1")] // 如果Conditional特性检测到有宏定义Text1 那么就执行Method1方法,如果没有检测到,就不执行
public static void Method1()
{
Console.WriteLine("Method1");
}
public static void Method2()
{
Console.WriteLine("Method2");
}
static void Main(string[] args)
{
Method1();
Method2();
Console.ReadKey();
}
}
}
————————————————————————————————————————————方法的Caller特性(调用者信息特性)
这个特性是添加在方法的参数前面的,返回调用者的信息,实例如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.CompilerServices;
using System.Diagnostics;
namespace 调用来源
{
class Program
{
[DebuggerStepThrough]
public static void Method1 (int a,[CallerFilePath]string fileName=" ",[CallerLineNumber]int linenumber=1,[CallerMemberName]string methodName=" ")
{
Console.WriteLine(a);
Console.WriteLine(fileName+"***调用文件");
Console.WriteLine(linenumber+"***代码行数");
Console.WriteLine(methodName+"***调用成员");
}
static void Main(string[] args)
{
Method1(7895);
Console.ReadLine();
}
}
}
自定义特性:
特性:特性(attribute)是一种允许我们向程序的程序集增加元数据的语言结构。它是用于保存程序结构信息的某种特殊类型的类。
可以用于监测一些程序里的类,方法的调用;
特性的定义:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 自定义特性类
{
//1.自定义特性必须继承自System.Attribute类
//2.自定义特性类一般声明为sealed(不可继承的)
//3.在自定义的特性类里一般不会声明方法(定义一些字段和属性)
//4.声明特性类必须以Attribute结尾
//5.调用特性相当于调用特性的命名方法
[AttributeUsage(AttributeTargets.Class)] //该特性用于定义自定义特性的适用范围 参数为attribute的一些枚举变量
sealed class MyTestAttribute:System.Attribute
{
public string tag { get; set; }
public MyTestAttribute(string temp)
{
this.tag = temp;
}
}
}
特性类的使用:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.CompilerServices;
namespace 自定义特性类
{
[MyTest("该特性已经被调用")]
class Program
{
static void Main(string[] args)
{
//关于特性的使用
//当消费者使用程序集的时候才会调用特性
//消费者程序包括:CLR,编译器,浏览器
//在源码里调试特性一般方法如下;
Type type = typeof(Program);
object[] array = type.GetCustomAttributes(false);
MyTestAttribute temp = array[0] as MyTestAttribute;
Console.WriteLine(temp.tag);
Console.ReadKey();
}
}
}
关于线程:
线程主程序:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
namespace 线程和进程
{
class Program
{
static void Main(string[] args)
{
//一、异步线程的开启方式
//1.委托开启
//Func<int,int> Act = Method1; //将需要进行的异步操作赋值给一个委托
//IAsyncResult e= Act.BeginInvoke(100,null,null); //调用这个委托的BeginInvoke方法开启一个新的线程,返回值是一个IAsyncResult(用于显示进程的状态的类)
//2.Thread对象(开启静态方法)
//Thread t = new Thread(Method2); //thread类型的构造函数方法必须是void(没有返回值的),并且参数必须是object类型
//t.Start("进程Id:"+Thread.CurrentThread.ManagedThreadId+" ");
//3.Thread对象(开启自定义类)
//Mythread my = new Mythread("进程需要的参数"); //在这里给进程传递参数
//Thread t = new Thread(my.StartThreat); //开启类里面的进程方法
//·····t.Start(); //不在这里传导参数
//4.通过线程池来开启线程
//ThreadPool.QueueUserWorkItem(Method2); //Method2必须有object参数,通过线程池开启的线程一定是后台线程,无法修改为前台线程
//5.通过任务开启
//Task t = new Task(Method3);
//t.Start();
//ro
//TaskFactory tf = new TaskFactory();
//tf.StartNew(Method3);
//任务是具有父子关系的夫人物执行完了才会执行子任务
//Task t2 = t.ContinueWith(Method4);
//Task t3 = t2.ContinueWith(Method4);
//Task t4 = t.ContinueWith(Method4);
//在这里任务t2与t4是同级关系
//二、判断线程结束的方式:
//1.循环判断线程执行状态(笨办法)
//while(e.IsCompleted==false) //用死循环判断进程的状态
//{
// Thread.Sleep(100); //没判断一次休眠100ms,用于控制判断的频率
// Console.Write("线程工作中。。。\n"); //线程正在运行的标记
//}
//2.等待句柄方式
//bool res = e.AsyncWaitHandle.WaitOne(2000); //在main线程里最多等待Act线程2s,返回值为线程是否执行完的bool值
//if (res) //这里线程没有执行完,不执行if里的代码块
//{
// var a = Act.EndInvoke(e);
// Console.WriteLine(a);
//}
//3.使用回调函数
//当开启新线程的时候,进行操作
//Func<int, int> Act = Method1;
//IAsyncResult res = Act.BeginInvoke(50, CallBack,Act); //委托开启方式,第一个参数是异步线程的参数,第二参数是委托类型的回调函数,第三个参数是回调函数的参数
//四、前台线程和后台线程
//Thread 类声明默认是前台线程,当程序的前台线程结束的时候程序就结束了(他会结束所有的后台线程)
//Thread t = new Thread(Method2);
//t.Start();
//五、线程争用和死锁问题
//1.线程争用
//Mythread m = new Mythread("这里没用到"); //声明一个线程调用的对象
//Thread t1 = new Thread(Method5); //开启线程t1调用m
//t1.Start(m);
//Thread t2 = new Thread(Method5); //开启线程t2调用m
//t2.Start(m);
//以上的情况就是线程争用解决这个问题的方法是使用线程锁(lock)
//2.线程死锁问题(目前为死锁状态)改变线程方法里的对象锁定顺序可以修复改bug
Mythread m = new Mythread("这里没用到"); //线程目标对象1
Mythread n = new Mythread("这里没用到"); //线程目标对象2
Threadparameter pa = new Threadparameter(m, n); //线程多参数类
Thread t1 = new Thread(Method6); //开启线程t1调用m
t1.Start(pa);
Thread t2 = new Thread(Method7); //开启线程t2调用m
t2.Start(pa);
Console.WriteLine("main函数执行标记"); //main线程的标记
//var a=Act.EndInvoke(e); //取得异步线程的返回值(在Main线程内,main线程执行到这里回默认等待线程执行结束),避免在线程没有结束时使用该语句
Console.ReadKey();
}
//回调函数
static void CallBack(IAsyncResult temp) //回调函数的参数必须是异步线程执行状态(IAsyncResult)变量
{
// ...otherfuction...
// 在回调函数中取得异步线程返回值(如有i需要写法如下)
Func<int, int> temp2 = temp.AsyncState as Func<int, int>; //从异步线程执行状态变量(temp)访问到异步线程 temp2
var res_Fuc = temp2.EndInvoke(temp); //取得异步线程的返回值
Console.WriteLine("回调函数执行完毕"+res_Fuc);
}
//需要开启的异步线程
static int Method1 (int a) //有自定义参数的方法
{
Thread.Sleep(3000); //模拟一个比较耗时的线程
Console.WriteLine(a + "Method1");
return a*2;
}
static void Method2( object temp ) //需要object类型参数的方法
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
Console.WriteLine(temp + "不需要返回值的静态方法线程");
Thread.Sleep(2000); //线程休眠2秒(模拟任务)
}
static void Method3() //不需要参数的方法1(在任务里作为父任务)
{
Console.WriteLine("父线程开启");
Thread.Sleep(2000);
Console.WriteLine("父线程结束");
}
static void Method4(Task temp) //不需要参数的方法2(在任务里作为子任务)
{
Console.WriteLine("子任务开启");
Thread.Sleep(4000);
Console.WriteLine("子任务结束");
}
static void Method5(object temp1) //线程争用问题的循环访问方法
{
Mythread temp2 = temp1 as Mythread;
while (true)
{
lock (temp2) //使用线程锁解决线程争用问题
{
temp2.Changetag();
}
}
}
static void Method6(object para) //线程争用演示线程1
{
Threadparameter Thpara = para as Threadparameter;
Mythread a = Thpara.para1 as Mythread;
Mythread b = Thpara.para2 as Mythread;
while(true)
{
lock (b)
{
lock (a)
{
Console.WriteLine("没有卡住");
}
}
}
}
static void Method7(object para) //线程争用演示线程2
{
Threadparameter Thpara = para as Threadparameter;
Mythread a = Thpara.para1 as Mythread;
Mythread b = Thpara.para2 as Mythread;
while (true)
{
lock (a)
{
lock (b)
{
Console.WriteLine("没有卡住");
}
}
}
}
}
}
线程类:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 线程和进程
{
class Mythread //异步线程类
{
private string parameter;
private int tag = 5;
public Mythread(string temp)
{
this.parameter = temp;
}
public void StartThreat()
{
Console.WriteLine(this.parameter+"\n进程执行ing");
}
public void Changetag()
{
this.tag--;
if (tag == 5)
{
Console.WriteLine("还是五");
}
this.tag = 5;
}
}
}
线程多参数类:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 线程和进程
{
class Threadparameter // 线程参数类
{
public object para1;
public object para2;
public Threadparameter(object temp1,object temp2)
{
this.para1 = temp1;
this.para2 = temp2;
}
}
}
socket 心跳包制作:
http://www.cnblogs.com/xugang/archive/2008/04/15/1154689.html
C# JAVA 去除数组里的空元素
(在C# 和 Java的语法里数组一经声明是无法改变长短的,我们使用List<T>来改变数组)
下面是去掉字符数组里的空元素的例子
List<char> clist = cres.ToList();
Console.WriteLine("::::::::::::::::::;" + (int)clist[0]);
while(true)
{
if ((int)clist[0]==0)
{
clist.RemoveAt(0);
}
else {
break;
}
}
cres = clist.ToArray();