C#高级编程笔记 (6至10章节)运算符/委托/字符/正则/集合

时间:2022-07-04 19:29:19

数学的复习,4^-2即是1/4/4的意思, 4^2是1*2*2的意思,而10^-2为0.01!

7.2运算符

符号 说明  
++ 操作数加1 int i=3; j=i++; 运算后i的值为4,j的值为3
    int i=3; j=++i; 运算后i的值为4,j的值为4
-- 操作数减1 int i=3; j=i--; 运算后i的值为2,j的值是3
    int i=3, j=--; 运算后i的值为2,j的值是2
&& 执行逻辑运算,检查两个表达式是否为真 int a=5;(a<10&&A>5) False
|| 执行逻辑运算,检查两个表达式是否至少有一个为真 int a=5;(a<10||A>5) true
& 并集 AND    
| 或集 OR    
typeof 表示某种数据类型,返回类型 typeof(string) 返回字符类型
?: 简化的IF语句 表达式?语句1:语句2 表达式为真时,执行语句1,否语句2

checked运算符可以检查类型强制转换是否安全 如果不如全会抛出一个溢出异常    checked((int)变量1)

checked在自定义类的强制转换时应有重载过程中检查,不应放在Main或调用时

int? 表示int可空类型,可以表示NULL  如 int? a = null;                              uint 表示无符号的int类型

字符串转换为数值int i = int.parse("100")

7.4.1比较引用类型的相等性(相关说明)

== 在比较值类型的时候,会自动转换并比较数值,如果值一样输出True;

== 在比较引用类型时,一般情况下比较的这是引用类型的引用是否相等;

Equals 与 ==相同(其中不同的地方是不会自动转换) 即: int i =5;double n =5 ,i.Equals(n)为False

ReferenceEquals 则不管是什么类型都只比较引用是否相同,因值类型需要装箱,部是返回false,所以值类型调用这个方法没什么意义!

7.5运算符的重载

operator重载运算符 C#要求所有的运算符重载都声明为public与static,运算符左边的参数命名为lhs,运算符右边的参数命名为rhs

public static Vector operator + (vector lhs, vector rhs)
{
Vector result = new Vector(lhs);
result.x += rhs.x;
return result;
}

并不是所有的运算符都可以重载,可以重载的运算符如下表

类别 运算符 限制
算术二元运算符 +、*、/、-、%、
算术一元运算符 +、-、++、--
按位二元运算符 &、|、^、<<、>>
按位一元运算符 !、~、true、false true与false运算符必须成对重载
比较运算符 ==、!=、>=、<、<=、> 比较运算符必须成对重载
赋值运算符 +=、-=、*=、/=、>>=、<<=、%=、&=、|=、^= 不能显式地重载这些运算符,在重写单个运算符(如+、-、%等)时,它们会被隐式地重写
索引运算符 [] 不能直接重载索引运算符,第2章介绍的索引器成员类型允许在类和结构上支持索引运算符
数据类型强制转换运算符 () 不能直接重载类型强制转换运算符,用户定义的类型强制转换(本章的后面介绍)允许定义定制的类型强制转换行为

7.6用户定义的类型强制转换

public class Rational
{
private Int32 _inner_int = ;
public Rational()
{
}
public Rational(Int32 num)
{
this._inner_int = num;
}
public Int32 ToInt32() { return this._inner_int; }
// 隐式构造并返回一个合理的从一个Int32
public static implicit operator Rational(Int32 num)
{
return new Rational(num);
}
// 显式返回一个合理的Int32
public static explicit operator Int32(Rational r)
{
return r.ToInt32();
}
public override string ToString()
{
//return base.ToString();
String s = String.Format("{0}", this._inner_int);
return s;
}
}
class Program
{
static void Main(string[] args)
{
Rational r1 = ;
Console.WriteLine(r1); //隐式转换 Int32 i =(Int32) r1; //Rational转换成 Int32时,指定了explicit(显式的),所以必须要指定转换类型Int32,如果将explicit换成implicit(隐式),int32i = r1 的代码将可以正常运行
Console.WriteLine(i);
Console.ReadLine();
}
}

8.2.3简单的委托示例

下面代码:实例化了一个委托数组DoubleOp(温馨提示:一旦定义了委托,基本就可以实例化它了,那么就可以像处理类那样,使用该委托了,所以这里把一些委托的实例放到数组中是可以的)。数组被初始化为由MathsOperations类实现的不同操作。然后遍历该数组,把每个操作应用到3个不同的值上,这恰好说明了委托的一种方式:把方法组合到一个数组中来使用,这样就实现了在循环中调用不同的方法了

using System;

namespace Wrox.ProCSharp.Delegates
{
delegate double DoubleOp(double x);//定义 DoubleOp委托的数组,参数为X class Program
{
static void Main()
{ DoubleOp[] operations =
{
MathOperations.MultiplyByTwo,
MathOperations.Square
};//把MathOperations类的方法封装到委托的数组中! for (int i = ; i < operations.Length; i++)
{
Console.WriteLine("Using operations[{0}]:", i);
ProcessAndDisplayNumber(operations[i], 2.0);
ProcessAndDisplayNumber(operations[i], 7.94);
ProcessAndDisplayNumber(operations[i], 1.414);
Console.WriteLine();
}
Console.ReadLine();
}
/// <summary>
///
/// </summary>
/// <param name="action">参数1:理解引入一个已选择好的委拖的方法,类型为委托类型</param>
/// <param name="value">参数2:</param>
static void ProcessAndDisplayNumber(DoubleOp action, double value)
{
double result = action(value);//调用委托,然后参数为value
Console.WriteLine(
"Value is {0}, result of operation is {1}", value, result);
}
}
class MathOperations
{
public static double MultiplyByTwo(double value)
{
return value * ;
} public static double Square(double value)
{
return value * value;
}
}
}

8.2.4 Action<T>和Func<T>

泛型Action<in T>委托表示一个void返回类型的方法,    Func<in T1,out TResult>允许调用带返回类型的方法

using System;
namespace Wrox.ProCSharp.Delegates
{
class Program
{
static void Main()
{
Func<double,double>[] operations =
{
MathOperations.MultiplyByTwo,
MathOperations.Square
};//把MathOperations类的方法封装到委托的数组中! for (int i = ; i < operations.Length; i++)
{
Console.WriteLine("Using operations[{0}]:", i);
ProcessAndDisplayNumber(operations[i], 2.0);
ProcessAndDisplayNumber(operations[i], 7.94);
ProcessAndDisplayNumber(operations[i], 1.414);
Console.WriteLine();
}
Console.ReadLine();
}
static void ProcessAndDisplayNumber(Func<double, double> action, double value)
{
double result = action(value);//调用委托,然后参数为value
Console.WriteLine(
"Value is {0}, result of operation is {1}", value, result);
}
}
class MathOperations
{
public static double MultiplyByTwo(double value)
{
return value * ;
} public static double Square(double value)
{
return value * value;
}
}
}

Func示例

8.2.5 BubbleSoter委托示例

class Program
{
static void Main()
{
Employee[] employees =
{
new Employee("Bugs Bunny", ),
new Employee("Elmer Fudd", ),
new Employee("Daffy Duck", ),
new Employee("Wile Coyote", 1000000.38m),
new Employee("Foghorn Leghorn", ),
new Employee("RoadRunner", )
}; BubbleSorter.Sort(employees, Employee.CompareSalary);//传入参数1:数据,转入比较的方法 foreach (var employee in employees)
{
Console.WriteLine(employee);
}
Console.ReadLine(); }
}
class BubbleSorter
{
/// <summary>
///
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="sortArray">数据1表示可以按索引单独访问的对象</param>
/// <param name="comparison">方法,Func<T>委托,返回bool</param>
static public void Sort<T>(IList<T> sortArray, Func<T, T, bool> comparison)
{
bool swapped = true;
do
{
swapped = false;
for (int i = ; i < sortArray.Count - ; i++)
{
if (comparison(sortArray[i + ], sortArray[i]))
{
T temp = sortArray[i];
sortArray[i] = sortArray[i + ];
sortArray[i + ] = temp;
swapped = true;
}
}
} while (swapped);
}
}
class Employee
{
public Employee(string name, decimal salary)
{
this.Name = name;
this.Salary = salary;
} public string Name { get; private set; }
public decimal Salary { get; private set; } public override string ToString()
{
return string.Format("{0}, {1:C}", Name, Salary);
} /// <summary>
/// 比较二个数,类型参数1的工资小于e2为真,e2小于e1为假
/// </summary>
/// <param name="e1"></param>
/// <param name="e2"></param>
/// <returns></returns>
public static bool CompareSalary(Employee e1, Employee e2)
{
return e1.Salary < e2.Salary;
}
}

BubbleSoter示例

8.26多播委托

 class Program
{
static void Main()
{
Action<double> operations = MathOperations.MultiplyByTwo;//封装一个方法放至委托中
operations += MathOperations.Square;//多播委托,还支持-=从委托中删除调用 ProcessAndDisplayNumber(operations, 2.0);
ProcessAndDisplayNumber(operations, 7.94);
ProcessAndDisplayNumber(operations, 1.414);
Console.WriteLine();
Console.ReadLine();
} static void ProcessAndDisplayNumber(Action<double> action, double value)
{
Console.WriteLine();
Console.WriteLine("ProcessAndDisplayNumber called with value = {0}", value);
action(value); }
}
class MathOperations
{
public static void MultiplyByTwo(double value)
{
double result = value * ;
Console.WriteLine("Multiplying by 2: {0} gives {1}", value, result);
} public static void Square(double value)
{
double result = value * value;
Console.WriteLine("Squaring: {0} gives {1}", value, result);
}
}

多播委托示例

如果多播时如果一个委托方法出现异常,则整个迭代都会停止,可使用GetInvocationlist()按照调用顺序返回此多路广播委托的调用列表。

然后迭代delegates即可

Action d1 = One;
d1 += Two;
Delegate[] delegates = d1.GetInvocationList();

8.2.7 匿名方法

匿名方法不到跳到方法外部,也不能从外部跳入内部,匿名方法不能访问不安全的代码,

最好使用命名方法.C#3.0开始可以使用lambda代替匿名方法

static void Main()
{
string mid = ", 中间部分,"; Func<string, string> anonDel = delegate(string param)
{
param += mid;
param += " 这是要添加的字符串.";
return param;
};
Console.WriteLine(anonDel("开始字符串"));
Console.ReadLine();// 输出"开始字符串, 中间部分, 这是要添加的字符串.
}

8.3 lambda表达式

lambda表达式的应用 上面的方法改为如下

"datagate(string 变量1)" 改为 "变量1=>"

static void Main()
{
string mid = ", 中间部分,"; Func<string, string> anonDel = param=> // delegate(string param)
{
param += mid;
param += " 这是要添加的字符串.";
return param;
};
Console.WriteLine(anonDel("开始字符串"));
Console.ReadLine();// 输出"开始字符串, 中间部分, 这是要添加的字符串.
}

lambda 语句

func<double, double, double> twoParams = (x, y) =>x*y //方法内只有一条语句,会隐式添加return,多语句时要加花括号与return
func<double, double, double> twoParams = (double x,double y) =>x*y//如不能匹配重载后的版本可以使用参数类型帮助找到匹配的委托

8.3.3闭包

通过lambda表达式可以访问lambda表达式块外部的变量-称为闭包

int i = ;
Func<int, int> test = j => j * i;
Console.WriteLine(test());//输出12
i = ;
Console.WriteLine(test());//输出20
Console.ReadLine();

8.3.4 foreach闭包

var values = new list<int>() {,,};
var funcs = new list<Func<int>>();
foreach(var val in values)
{
var v =val; //在C# 5.0不需要这样处理,但是在C# 4 和之前需要这样 不然全输出30;
funcs.add(() => v);
}
foreach (var f in funcs)
{
Console.WritLine((f ()));
}

8.4 事件

事件理解可解: 一个是触发事件的类,一个是订阅这个事件的类, main主程式中订阅事件,事件有单独一下类!下面代码可以看出对应的关系

阅读《C# 高级编程》,其中关于EventHandler的使用颇让人费解。
因为已经习惯了public event delegateName eventName;这种定义事件的方式,因此下面结合这种方式来解释一下书中示例的代码。
先来看看CarDealer类的定义:

//CarInfoEventArgs 这类可以理解为是传递的参数,直接影响CarDealer顾客类中订阅的输出参数!
public class CarInfoEventArgs : EventArgs //EventArge表示包含事件数据的类的基类,并提供要用于不包含事件数据的事件的值。这个基类更像是规范性的基类,http://www.cnblogs.com/porter/p/5895132.html
{
public CarInfoEventArgs(string car)
{
this.Car = car + " 测试";
}
public string Car { get; private set; }
} public class CarDealer
{
public event EventHandler<CarInfoEventArgs> NewCarInfo; //定义一个事件NewCarInfo,当提供数据时触发 public void NewCar(string car) //main过程中调用
{
Console.WriteLine("汽车经销商, 新车 {0}", car); RaiseNewCarInfo(car);//调用RaiseNewCarInfo的方法
} protected virtual void RaiseNewCarInfo(string car)
{
EventHandler<CarInfoEventArgs> newCarInfo = NewCarInfo;
if (newCarInfo != null)
{
NewCarInfo(this, new CarInfoEventArgs(car));//这里触发事件,参数1本身,事件的发送者,参数2提供事件的相关信息
}
}
}

这里实际上先定义了一个继承自EventArgs的类,这个类的作用是用来储存将用来传递给事件的参数,在本例中,就是string成员Car,表示新车的名字。
然后在CarDealer类中,定义了事件NewCarInfo,类型是EventHandler<CarInfoEventArgs>,这是EventHanlder的泛型。EventHandler<T>表示一个接受两个参数(object sender, TEventArgs e),返回类型为void的方法。其中,TEventArgs必须为派生自EventArgs类的类型。后一个参数就是储存事件所需要参数用的。
然后是两个方法,其中RaiseNewCarInfo方法就是执行事件的方法。该方法由NewCar方法调用,接受string参数。而NewCar方法开放给汽车销售商,每到一辆新车,就执行一次这个方法,执行需要把新车的名字传递给方法。
然后我们来看客户Consumer类:

public class Consumer
{
private string name; public Consumer(string name)
{
this.name = name;
}
/// <summary>
/// 它的签名符合EventHandler<CarInfoEventArgs>类型:返回类型为void,接受一个object参数和一个CarInfoEventArgs参数。这就是Event事件可以接受的方法。
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public void NewCarIsHere(object sender, CarInfoEventArgs e)
{
Console.WriteLine("{0}: 汽车 {1} 是新的", name, e.Car);
}
}

客户类定义了字段name用来储存客户名,这个name会在NewCarIsHere方法中使用到。重点就是这个NewCarIsHere方法,观察可知,它的签名符合EventHandler<CarInfoEventArgs>类型:返回类型为void,接受一个object参数和一个CarInfoEventArgs参数。这就是Event事件可以接受的方法。
因此在Main类中执行的方法就很简单了

static void Main()
{
var dealer = new CarDealer(); //汽车经销商 var michael = new Consumer("顾客 迈克尔"); //消费者
dealer.NewCarInfo += michael.NewCarIsHere;//NewCarIsHere方法加入NewCarInfo事件 dealer.NewCar("法拉利"); var nick = new Consumer("顾客 塞巴斯蒂安"); //消费者
dealer.NewCarInfo += nick.NewCarIsHere; dealer.NewCar("Mercedes");
Console.WriteLine(); dealer.NewCarInfo -= michael.NewCarIsHere; //移除消费者的事件,这里不会触发 迈克尔NewCarIsHere方法 dealer.NewCar("Red Bull Racing");
Console.ReadLine();
}

http://blog.csdn.net/cyh1992899/article/details/52806690

8.4.3 弱事件(system.Windows)

弱事件管理器

使用弱事件需创建一个派生自WeakEventManager类的管理器类,这个类要实现单态模式!

弱事件管理类需在静态方法Addlistener()和RemoveListener(),用来添加和删除侦听器

还在重写基类的StartListening()和StopListening()方法

public class WeakCarInfoEventManager1 : WeakEventManager
{
/// <summary>
/// 新汽车事件管理器1
/// </summary>
public static WeakCarInfoEventManager1 CurrentManager
{
get
{
WeakCarInfoEventManager1 manager = GetCurrentManager(typeof(WeakCarInfoEventManager1)) as WeakCarInfoEventManager1;
if (manager == null)
{
manager = new WeakCarInfoEventManager1();
SetCurrentManager(typeof(WeakCarInfoEventManager1), manager);//为指定的管理器类型设置当前管理器。
}
return manager;
}
}
public static void AddListener(object source, IWeakEventListener listener) //添加订阅(侦听器)事件
{
CurrentManager.ProtectedAddListener(source, listener);
} public static void RemoveListener(object source, IWeakEventListener listener)//移除订阅(侦听器)事件
{
CurrentManager.ProtectedRemoveListener(source, listener);
} void CarDealer_NewCarInfo(object sender, CarInfoEventArgs1 e)//参数1,参数2表示传递类
{
DeliverEvent(sender, e); //将正在托管的事件传送到每个侦听器。
}
protected override void StartListening(object source)//重写基类方法
{
(source as CarDealer).NewCarInfo += CarDealer_NewCarInfo; //CarDealer为事件发送者类(事件源?)
}
protected override void StopListening(object source)//重写基类方法
{
(source as CarDealer).NewCarInfo -= CarDealer_NewCarInfo;
}
}

发布程序类

public class CarInfoEventArgs1 : EventArgs
{
public CarInfoEventArgs1(string car)
{
this.Car = car+" 从事件中传递的";
} public string Car { get; private set; }
} public class CarDealer
{
public event EventHandler<CarInfoEventArgs1> NewCarInfo; public CarDealer() //实例化类用
{
}
public void NewCar(string car)
{
Console.WriteLine("CarDealer, new car {0}", car);
if (NewCarInfo != null)
{
NewCarInfo(this, new CarInfoEventArgs1(car));
}
}
}

事件侦听器类

public class Consumer : IWeakEventListener // 接收事件的类提供事件侦听支持
{
private string name;
public Consumer(string name)
{
this.name = name;
}
public void NewCarIsHere(object sender, CarInfoEventArgs1 e)
{
Console.WriteLine("{0}: 汽车 {1} 是新的", name, e.Car);
}
bool IWeakEventListener.ReceiveWeakEvent(Type managerType, object sender, EventArgs e) //接收集中事件管理器中的事件。
{
NewCarIsHere(sender, e as CarInfoEventArgs1);
return true;
}
}
public class test : IWeakEventListener
{
public void test1(object sender, CarInfoEventArgs1 e)//
{
Console.WriteLine(" 测试类触发了 {0} ", e.Car);
}
bool IWeakEventListener.ReceiveWeakEvent(Type managerType, object sender, EventArgs e) //接收集中事件管理器中的事件。
{
test1(sender, e as CarInfoEventArgs1);
return true;
}
}

main()

static void Main()
{
var dealer = new CarDealer();
var michael = new Consumer("小明");
var pray = new test();
WeakCarInfoEventManager1.AddListener(dealer, michael);
WeakCarInfoEventManager1.AddListener(dealer, pray);
dealer.NewCar("凯帝");
var sebastian = new Consumer("小花");
WeakCarInfoEventManager1.AddListener(dealer, sebastian);
sebastian = null;
dealer.NewCar("宝马");
WeakCarInfoEventManager1.RemoveListener(dealer, michael);
dealer.NewCar("Red Bull Racing");
Console.ReadLine();
}

输出:

CarDealer, new car 凯帝
小明: 汽车 凯帝 从事件中传递的 是新的
测试类触发了 凯帝 从事件中传递的
CarDealer, new car 宝马
小明: 汽车 宝马 从事件中传递的 是新的
测试类触发了 宝马 从事件中传递的
小花: 汽车 宝马 从事件中传递的 是新的
CarDealer, new car Red Bull Racing
测试类触发了 Red Bull Racing 从事件中传递的
小花: 汽车 Red Bull Racing 从事件中传递的 是新的

相关弱事件请参考8.4.3节查看与读解!

泛弱事件管理器

,net 4.5 为弱事件提供了新的实现。泛型类 WeakEventManager<TEventSource, TEventArgs>,它派生自基类WeakEventManager,大大的简化了弱事件的处理

static void Main(string[] args)
{
var dealer = new CarDealer(); //事件源类
var michael = new Consumer("Michael");//侦听器类
WeakEventManager<CarDealer, CarInfoEventArgs>.AddHandler(dealer, "NewCarInfo", michael.NewCarIsHere);
//WeakEventManager<事件源类,侦听器类>.AddHandler(事件源实例,"事件",侦听器类.侦听器事件方法)
dealer.NewCar("Mercedes");
var sebastian = new Consumer("Sebastian");
WeakEventManager<CarDealer, CarInfoEventArgs>.AddHandler(dealer, "NewCarInfo", sebastian.NewCarIsHere);
dealer.NewCar("Ferrari");
WeakEventManager<CarDealer, CarInfoEventArgs>.RemoveHandler(dealer, "NewCarInfo", michael.NewCarIsHere);
dealer.NewCar("Red Bull Racing");
}

其它类与事件实例一样!事件源carDealer不同(省略了代码)

9.1 system.string类

方法 说明 格式 解释
compare 比较字符串 string.Compare(str1,str2); 返回 str1对比str2大于1,相等0,小于-1
compare 重载(忽略大小) string.Compare(str1,str2,true) 返回同上,参数3忽略大小,返回int
concat 合并字符串 string.concat(str1,str2) 返回合并多个字符串的合并为一个实例
copyto 复制到字符数组 str1.copy(2,char1,3,9) 把str1的索引2开始的9个字符复制到char1的索引3覆盖
Format 参数化处理 string.Format("今天{0}","天气") 返回"今天天气"字符串
IsNullOrEmpty 判断是否为空或Null sting.IsNullOrEmpty(str1) 返回str1=""或str=Null 返回True  否则false
Join 将数组的元素以分隔符拼接成一个新的字符串 string.Join(",",Arr1) 返回Arr1[0],Arr1[1],…… 以参数1分隔的字符串
Contains 判断字符串中存在某字符串 str1.Contains(str2) 返回存在返回true,不存在返回false
StartsWith 是否以字符串开头 str1.StarWith(str2) 返回如果str1开头是str2则true,否则false
EndsWith 是否以字符串结尾 str1.EndsWith(str2) 返回如果str1结尾是str2则true,否则false
IndexOf 等一次出现的位置 str1.indexof(str2) 返回str2等一次在str1的位置(索引值),如果不存在返回-1
lsatIndexOf 最后一次出现的位置 str1.indexof(str2) 返回str2最后一次在str1的位置(索引值),如果不存在返回-1
Equals 是否相等 str1.Equals(str2) 返回如果相等,则true,否则false
Replace 替换 str1.Replace("中","上") 返回把str1的"中"替换为"上"的新字符串
Insert 插入 str1.Insert(2,str2) 返回 把str2插入到str1的位置2的新字符串
Remove 删除 str1.Remove(1,2) 返回 删除位置1,长度2的新字符串
split 返回以字符分割字符 str1.split(',')
str1.split(char1[])
返回 以','分割的字符串数组,或以char1[]分割
substring 截取字符串 str1.substring(3,2) 返回 str1位置3,长2的新字符串
ToCharArray 字符串转换为字符数组 str1.ToCharArray() 返回字符数组
Trim 去两边的空格 str1.trim() 返回去掉str1两边的空格的新字符串
ToUpper 转换大写 str1.ToUpper() 返回str1的大写字符串
ToLower 转换小写 str1.ToLower() 返回str1的小写字符串

9.1.2 StringBuilder成员

方法 说明 格式 解释
Append 追加字符串到结尾 Bstr.Append("") 追加字符串到结尾
AppendFormat 追加格式字符串到结尾 Bstr1.AppendFormat("{0:C}", Int); 格式化结果到字符串中
Insert 插入字符到指定索引 Bstr1.Insert(6,str2) 在Bstr1的位置6插入
Remove 移除指定位置与数量的字符 Bstr1.Remove(5,7) 移除Bstr1位置5,7个字符
Replace 替换指定的字符 Bstr1.Replace("A","a") 把A替换为a

stringBuilder不能显式或隐式转换为string,只能使用tostring()方法

格式          
C 数字 货币 string.Format("{0:C}",0.2) ¥0.20 {0:C1} 为0.2 四舍五入
D 整数 整数 string.Format("{0:D3}",23) 023 补全3位
E 数字 科学计数 string.Format("{0:E2}", 123456) 1.23E+005 科学计数
F 数字 小数点后的倍数 string.Format("{0:F4}", 15) 15.0000 精确位数
G 数字 一般的数字 string.Format("{0:E2}", 123456) 1.23456E5 -
N 数字   string.Format("{0:N}", 14200) 14,200.00 {0:N3}为14,200.000
P 数字 百分比 string.Format("{0:P}", 0.24583) 24.58% {0:P1}为24.6%
X 整数 十六进制 string.Format("0x{0:X}", 60) 0x3C 十六进制60
0与# 数字 0表示显示 "{0:0000.00} 与{0:####.#)",194.039 0194.03与194  

9.2正则表达式 system.text.RegularExpressions

Match mat = regex.match(str1,regstr,RegexOptions.IgnoreCase);  //match表示只匹配第一个!

MatchCollection matchCol = Regex.Matches(str1,regstr,RegexOptions.IgnoreCase);//表示匹配所有字符,matchcol可迭量

RegexOptions选项说明 (多个选项可用"|"分隔,可省略)

Singleline 正则的"."匹配\n 默认不匹配\n
IgnoreCase 不区分大小 默认区分大小写
RightToLeft 从右到左开始匹配(运行) 默认从左到右
Multiline 匹配多行 默认不匹配字符串的多行
ExplicitCapture 指定只有显式命名或编号的组才进行捕获,即不想用"?:"时 这个当做贤学就好了- -(不懂)

9.2.4匹配、组合各捕获

()表示组合

?:a 表示要匹配a便是不保存a     与a?的区别在于保存

10集合system.Collections

10.2集合接口和类型

官方说明档 相关的集合理解介绍

接口 说明
IEnumerable<T> 实现foreach语句,这个接口定义了GetEnumerator()的方法 ,返回一个实现了IEnumerator接口的枚举,如下:
IDictionaryEnumerator enumerator = hastable.GetEnumerator();
while (enumerator.MoveNext())
{
string key = enumerator.Key.ToString();
string value = enumerator.Value.ToString();
}
ICollection<T> 获取元素的数量、增加删除元素 相关连接
IList<T> 表示可按照索引单独访问的对象的非泛型集合。派生自ICollection.add()
   
   
   
   
   

list<int> intlist = new list<int>(10);//10个元素

intlist.Capacity = 20;//集合的容量

intlist.count;//元素的个数

intlist.TrimExcess();//清理容量,注元素超90%容量时不清理

add()

属性  
Capacity 容量大小
count 元素的个数
方法  
TrimExcess() 清理容量,注元素超90%容量时不清理
Insert() 插入元素 list.insert(3,new racer(6,"")) 插入到3位置
add() 添加元素 list.add(new racer())
addRange() 添加元素数组 list.addRange(new racer []{}) 把一另一个数组的元素添加入来
RemoveRange() 删除元素,可删除多个RemoveRange(3,5)删除位置3的5个元素
Indexof() 返回在数组中可以找到给定元素的第一个索引,如果不存在,则返回-1。 相关连接
lastIndexOf() 找到最后一个返回索引,没找到返回-1相关连接
findIndex() 返回数组中满足提供的测试函数的第一个元素的索引。否则返回-1相关连接
find() 返回数组中满足提供的测试函数的第一个元素的值相关连接
findAll() 返回数组中满足提供的测试函数的所有元素项相关连接
Sort() 对元素进行排序 ,要实现IComparable接口,才能使用 连接Sort方法
ConvertALL() 将当前 List<T> 中的元素转换为另一种类型,并返回包含已转换元素的列表 相关说明
AsReadOnly() 只读集合

findindex()方法

// 学生类
class Stu
{
public string Name { get; set; }
public int Age{get;set;}
} //泛型列表
List<Stu> list = new List<Stu>();
list.Add(new Stu(){Name="zhang", Age=});
list.Add(new Stu(){Name="Li", Age=});
list.Add(new Stu(){Name="Wang", Age=});
list.Add(new Stu(){Name="Liu", Age=}); //FindIndex
int index = list.FindIndex(s=>s.Name=="Liu"); //index = 3;
index = list.FindIndex(s=>s.Name=="Li"); //index = 1;

10.4队列

10.6链表

LinkedList< T> . AddAfter()//在 LinkedList< T> 中的现有节点后添加新的节点或值。

LinkedList< T> . AddBefore()

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.IO;
using System.Text.RegularExpressions; namespace ConsoleApplication1
{
class Program
{ static void Main(string[] args)
{
PriorityDocumentManager pdm = new PriorityDocumentManager();
pdm.AddDocument(new Document("one", "Sample", ));
pdm.AddDocument(new Document("two", "Sample", ));
pdm.AddDocument(new Document("three", "Sample", ));
pdm.AddDocument(new Document("four", "Sample", ));
pdm.AddDocument(new Document("five", "Sample", ));
pdm.AddDocument(new Document("six", "Sample", ));
pdm.AddDocument(new Document("seven", "Sample", ));
pdm.AddDocument(new Document("eight", "Sample", )); pdm.DisplayAllNodes();
Console.ReadLine(); }
}
public class PriorityDocumentManager
{
/// <summary>
/// 包括所有的文档的比重链接列表
/// </summary>
private readonly LinkedList<Document> documentList; /// <summary>
/// 包括最多10个元素的引用
/// </summary>
private readonly List<LinkedListNode<Document>> priorityNodes; public PriorityDocumentManager()
{
documentList = new LinkedList<Document>(); priorityNodes = new List<LinkedListNode<Document>>();
for (int i = ; i < ; i++)
{
priorityNodes.Add(new LinkedListNode<Document>(null));
}
} public void AddDocument(Document d)
{
if (d == null) throw new ArgumentException("参数d不能为空。"); //如果值为空的时候,引发异常信息
AddDocumentToPriorityNode(d, d.Priority); //传替一个实例,和这个实例的优先级
}
/// <summary>
///
/// </summary>
/// <param name="doc">Document实例</param>
/// <param name="priority">优先级</param>
private void AddDocumentToPriorityNode(Document doc, int priority)
{
if (priority < || priority >= ) throw new ArgumentException("优先级必须介于0到9之间。");
if (priorityNodes[priority].Value == null)
{
--priority;
if (priority >= )
{
//检查下一个较低优先级
AddDocumentToPriorityNode(doc, priority);
}
else // 现在没有具有相同优先级或更低优先级的节点存在。 // 将新文档添加到结尾
{
documentList.AddLast(doc);
priorityNodes[doc.Priority] = documentList.Last;
}
return;
}
else // 存在一个优先级节点
{
LinkedListNode<Document> prioNode = priorityNodes[priority];
if (priority == doc.Priority)
// 存在相同优先级的优先级节点
{
documentList.AddAfter(prioNode, doc);// prioNode修改节点信息,其后面的链为doc // 将优先级节点设置为具有相同优先级的最后一个文档
priorityNodes[doc.Priority] = prioNode.Next;// doc修改节点信息,其前面的链为prioNode
}
else // 只有较低优先级的优先级节点存在
{
// 获取较低优先级的第一个节点。
LinkedListNode<Document> firstPrioNode = prioNode; while (firstPrioNode.Previous != null &&
firstPrioNode.Previous.Value.Priority == prioNode.Value.Priority)
{
firstPrioNode = prioNode.Previous;
prioNode = firstPrioNode;
} documentList.AddBefore(firstPrioNode, doc); // 将优先级节点设置为新值
priorityNodes[doc.Priority] = firstPrioNode.Previous;
}
}
} public void DisplayAllNodes()
{
foreach (Document doc in documentList)
{
Console.WriteLine("priority: {0}, title {1}", doc.Priority, doc.Title);
}
} // 返回具有最高优先级的文档
// (这是链接列表中的第一个)
public Document GetDocument()
{
Document doc = documentList.First.Value;
documentList.RemoveFirst();
return doc;
} }
public class Document
{
public string Title { get; private set; } //标题
public string Content { get; private set; } //内容
public byte Priority { get; private set; } //优先 public Document(string title, string content, byte priority)
{
this.Title = title;
this.Content = content;
this.Priority = priority;
}
}
}

10.7有序列表

SortedList< TKey, TValue>  //有序列表会自动排序

add方法SortedList1.add("name","1");

foreach (KeyValuePair<string,string> item in strSortedList)//这里用VAR省事- -
{
Console.WriteLine(item.Key);
} ///其它特性基本都是一样的
Console.ReadLine();

strSortedList.ContainsKey("name");//确定 SortedList<TKey, TValue> 是否包含特定的键。存在为trun,否则false

strSortedList.TryGetValue("环境变化", out str1 );//获取与指定参数1的值,传替到STR1,不存在时返回值为False

10.8字典

字典的关系:    键<->索引<->值   ,net提供了几个字典类,可以使用的最主要的类是Dictionary<TKey,TValue>

请查阅书籍中内容 网上内容

10.8.3lookup类

类新类Lookup<TKey, TElement>是.NET 3.5中新增的,它类似于Dictionary<TKey, TValue>,但把键映射到一个值集上。这个类在程序集System.Core中实现,用System.Linq命名空间定义。相关连接

10.8.4有序字典

SortedList<TKey,TValue>有序列表类使用的内存要比SortedDictionary<TKey,TValue>类少

SortedDictionary<TKey,TValue>有序字典类的元素插入和删除操作比较快

10.9集

HashSet<string> companyTeams = new HashSet<string>() { "Ferrari", "McLaren", "Mercedes" };

privateTeams.Add("Williams")//如果已存在返回false

hashset1.IsSubsetOf(hashset2);// hashset1是hashset2的子集时返回true,  hashset2包括hashset1

hashset2.IsSupersetOf(hashset1); //hashset2是hashset1的超集时返回true

hashset1.Overlaps(hashset2);//hashset1与hashset2有交集的时候返回true

hashset1.UnionWith(hashset2);//修改hashset1的集合为hashset1与hashset2的合集

hashset1.ExcepWith(hashset2);//移除hashset1中hashset2的集合的元素

10.10可观性集合

static void Main()
{
var data = new ObservableCollection<string>();
data.CollectionChanged += Data_CollectionChanged; //添加到事件
data.Add("One");
data.Add("Two");
data.Insert(, "Three");
data.Remove("One");
Console.ReadLine();
} static void Data_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
Console.WriteLine("action: {0}", e.Action.ToString());//获取引发该事件的操作 if (e.OldItems != null)//获取受 Replace、Remove 或 Move 操作影响的各项的列表。
{
Console.WriteLine("starting index for old item(s): {0}", e.OldStartingIndex);//获取更改发生处的索引。
Console.WriteLine("old item(s):");
foreach (var item in e.OldItems)
{
Console.WriteLine(item);
}
}
if (e.NewItems != null)//获取更改中涉及的新项的列表
{
Console.WriteLine("starting index for new item(s): {0}", e.NewStartingIndex);//获取更改发生处的索引
Console.WriteLine("new item(s): ");
foreach (var item in e.NewItems)
{
Console.WriteLine(item);
}
}
Console.WriteLine();
}

10.11.1 BitArray类

BitArray类是一个引用类型

var bits1 = new BitArray(); //创建8位的数组   00000000
bits1.SetAll(true); //全部位数为1 11111111
bits1.Set(, false); //设置位数1是0 11111101
bits1[] = false; //设置位数5是0 11101101
bits1.Not(); //反转所有位数,即如果1则改为0,为0改为1
bits1.Or(bits2); //指定bits2元素对当前bits1元素执行按位“或”运算。101or100=101 满
bits2.And(bits1); //指定bits1元素对当前bits2元素执行按位“与”运算。101and100=100 二都是1时得1
bits1.Xor(bits2); //指定bits2元素对当前bits1元素执行按位“异或”运算。101xor100=111 不相同的时候为1
static void DisplayBits(BitArray bits)     //用于控制台输出01
{
foreach (bool bit in bits)
{
Console.Write(bit ? : );
}
}

10.11.2 BitVector32

效率比BitArray,在知道位数时可用BitVector32代替!它是一个值类型

var bits1 = new BitVector32();
int bit1 = BitVector32.CreateMask(); //这是1的位 (可以理解为是标记位置)掩码
int bit2 = BitVector32.CreateMask(bit1); //这是在bit1位上的
int bit3 = BitVector32.CreateMask(bit2); //这是在bit2位上的
int bit4 = BitVector32.CreateMask(bit3); //这是在bit3位上的
int bit5 = BitVector32.CreateMask(bit4); //这是在bit4位上的
bits1[bit1] = true; //设置位的值
bits1[bit2] = false;
bits1[bit3] = true;
bits1[bit4] = true;
//也可以这样设置 bits1[0x2] = true;设置倍十六进制的2的位数为1
BitVector32.Section sectionA = BitVector32.CreateSection(0xfff); //表示最底位的12位
Console.WriteLine("Section A: " + IntToBinaryString(bits2[sectionA], true));
static string IntToBinaryString(int bits, bool removeTrailingZero)//转为输出字符串
{
var sb = new StringBuilder();
for (int i = ; i < ; i++)
{
if ((bits & 0x80000000) != ) //bits或运算最高位
{
sb.Append(""); //追加到结尾
}
else
{
sb.Append("");
}
bits = bits << ; //左移1位
}
string s = sb.ToString();
if (removeTrailingZero)
return s.TrimStart('');
else
return s;
}

10.12不变的集合 System.Collectios.Immutable

List<Account> accounts = new List<Account>() {
new Account {
Name = "Scrooge McDuck",
Amount = 667377678765m
},
new Account {
Name = "Donald Duck",
Amount = -200m
}
};
ImmutableList<Account> immutableAccounts = accounts.ToImmutableList();//列表创建一个不变集合
ImmutableList<Account>.Builder builder = immutableAccounts.ToBuilder();//创建构建器
for (int i = ; i < builder.Count; i++)
{
Account a = builder[i];
if (a.Amount > ) //集合中Amount的值大于0移除
{
builder.Remove(a);
}
}
ImmutableList<Account> overdrawnAccounts = builder.ToImmutable();//转换为不变集合
foreach (var item in overdrawnAccounts)
{
Console.WriteLine("{0} {1}", item.Name, item.Amount);
}
Console.ReadKey();
}
 
//示例2
ImmutableArray<string> a1 = ImmutableArray.Create<string>();
ImmutableArray<string> a2 = a1.Add("Williams");
ImmutableArray<string> a3 = a2.Add("Ferrari").Add("Mercedes").Add("Red Bull Racing");

10.13并发集合

1)ConcurrentQueue:线程安全的先进先出 (FIFO) 集合

主要方法:
    Enqueue(T item);将对象添加到集合结尾。
    TryDequeue(out T result); 尝试移除并返回位于集合开始处的对象,返回值表示操作是否成功。
    TryPeek(out T result);尝试返回集合开始处的对象,但不将其移除,返回值表示操作是否成功。
说明:
    ConcurrentQueue是完全无锁的,但当CAS操作失败且面临资源争用时,它可能会自旋并且重试操作。
    ConcurrentQueue是FIFO集合,某些和出入顺序无关的场合,尽量不要用ConcurrentQueue。

2)ConcurrentStack:线程安全的后进先出 (LIFO) 集合

主要方法及属性:
    Push(T item);将对象插入集合的顶部。
    TryPop(out T result);尝试弹出并返回集合顶部的对象,返回值表示操作是否成功。
    TryPeek(out T result);尝试返回集合开始处的对象,但不将其移除,返回值表示操作是否成功。
    IsEmpty { get; }指示集合是否为空。
    PushRange(T[] items);将多个对象插入集合的顶部。
    TryPopRange(T[] items);弹出顶部多个元素,返回结果为弹出元素个数。
说明:
    与ConcurrentQueue相似地,ConcurrentStack完全无锁的,但当CAS操作失败且面临资源争用时,它可能会自旋并且重试操作。
    获取集合是否包含元素使用IsEmpty属性,而不是通过判断Count属性是否大于零。调用Count比调用IsEmpty开销大。
    使用PushRange(T[] items)和TryPopRange(T[] items)时注意缓冲引起的额外开销和额外的内存消耗。

3) ConcurrentBag:元素可重复的无序集合

主要方法及属性:
    TryPeek(out T result);尝试从集合返回一个对象,但不移除该对象,返回值表示是否成功获得该对象。
    TryTake(out T result);尝试从集合返回一个对象并移除该对象,返回值表示是否成功获得该对象。
    Add(T item);将对象添加到集合中。
    IsEmpty { get; }解释同ConcurrentStack
说明:
    ConcurrentBag为每一个访问集合的线程维护了一个本地队列,在可能的情况下,它会以无锁的方式访问本地队列。
    ConcurrentBag在同一个线程添加和删除元素的场合下效率非常高。
    因为ConcurrentBag有时会需要锁,在生产者线程和消费者线程完全分开的场景下效率非常低。
    ConcurrentBag调用IsEmpty的开销非常大,因为这需要临时获得这个无序组的所有锁。

4)BlockingCollection:实现System.Collections.Concurrent.IProducerConsumerCollection<T> 的线程安全集合,提供阻塞和限制功能

主要方法及属性:
    BlockingCollection(int boundedCapacity);boundedCapacity表示集合限制大小。
    CompleteAdding();将BlockingCollection实例标记为不再接受任何添加。
    IsCompleted { get; }此集合是否已标记为已完成添加并且为空。
    GetConsumingEnumerable();从集合中移除并返回移除的元素
    Add(T item);添加元素到集合。
    TryTake(T item, int millisecondsTimeout, CancellationToken cancellationToken);
说明:
    使用BlockingCollection()构造函数实例化BlockingCollection,意味着不设置boundedCapacity,那么boundedCapacity为默认值: int.MaxValue。
    限界:使用BlockingCollection(int boundedCapacity),设置boundedCapacity的值,当集合容量达到这个值得时候,向BlockingCollection添加元素的线程将会被阻塞,直到有元素被删除。
限界功能可控制内存中集合最大大小,这对于需要处理大量元素的时候非常有用。
    默认情况下,BlockingCollection封装了一个ConcurrentQueue。可以在构造函数中指定一个实现了IProducerConsumerCollection接口的并发集合,包括:ConcurrentStack、ConcurrentBag。
    使用此集合包含易于无限制等待的风险,所以使用TryTake更加,因为TryTake提供了超时控制,指定的时间内可以从集合中移除某个项,则为 true;否则为 false。

5)ConcurrentDictionary:可由多个线程同时访问的键值对的线程安全集合。

主要方法
    AddOrUpdate(TKey key, TValue addValue, Func<TKey, TValue, TValue> updateValueFactory);如果指定的键尚不存在,则将键/值对添加到 字典中;如果指定的键已存在,则更新字典中的键/值对。
    GetOrAdd(TKey key, TValue value);如果指定的键尚不存在,则将键/值对添加到字典中。
    TryRemove(TKey key, out TValue value);尝试从字典中移除并返回具有指定键的值。
    TryUpdate(TKey key, TValue newValue, TValue comparisonValue);将指定键的现有值与指定值进行比较,如果相等,则用第三个值更新该键。
说明:
    ConcurrentDictionary对于读操作是完全无锁的。当多个任务或线程向其中添加元素或修改数据的时候,ConcurrentDictionary使用细粒度的锁。使用细粒度的锁只会锁定真正需要锁定的部分,而不是整个字典。

6)IProducerConsumerCollection:定义供生产者/消费者用来操作线程安全集合的方法。 此接口提供一个统一的表示(为生产者/消费者集合),从而更高级别抽象如 System.Collections.Concurrent.BlockingCollection<T>可以使用集合作为基础的存储机制。

10.3.1管道

async 与 awair   async主要修饰方法, awair表示等待 相关理解

(1)在async标识的方法体里面,如果没有await关键字的出现,那么这种方法和调用普通的方法没什么区别。

(2)在async标识的方法体里面,在await关键字出现之前,还是主线程顺序调用的,直到await关键字的出现才会出现线程阻塞。

(3)await关键字可以理解为等待方法执行完毕,除了可以标记有async关键字的方法外,还能标记Task对象,表示等待该线程执行完毕。所以await关键字并不是针对于async的方法,而是针对async方法所返回给我们的Task。

(4)async要么是void,要么和Task关联

10.3.2使用BlockingCollection

1  在foreach循环中,用输入阻塞集合调用GetConsumingEnurnerable以迭化各项,好直接BlockingCollection变量,则只会迭代当前状态的集合,而不会迭代以后添加的项.

2  BlockingCollection.CompleteAdding方法是很重要的,否则读取器会在foreach循环中等待更多的项被添加