内容开始多了,慢品慢尝才有滋味。
一、命名空间namespace
用于解决类重名问题,可以看作类的文件夹.
若代码与被使用的类,与当前的namespace相同,则不需要using.
若namespace不同时,调用的方法:
1.写出全称:命名空间.类名
2.先using引用命名空间,再直接调用
在vs2022中
若引用的方法提示有误,鼠标指向有误处停2秒,会有灯光提示。
点击灯光,有就多种更正方式,包括加入引用。
或者,直接在有误处Alt+Shift+F10,也可快速提示。
同一解决方案下,项目B要使用项目A中的类:
1.解决方案中项目B下,右击引用,弹出窗口默认就是本解决方案中的项目 。
选择要引用的项目A,即引用项目A到项目B中。
2.引用命名空间:在最上面 using 项目A的命名空间
这样在项目B中就可以使用项目A中定义的类。
注意:在使用另一个项目中的类时,要注意访问修饰符。
vs中默认为internal,故应改为public.否则无法访问.
二、值类型与引用类型
值类型:int double,float,bool,char,enum,结构等
引用类型:string,数组,类等
值类型存储在栈(stack)中,
引用类型存储在堆(heap)中
三、字符串
1.字符串的不可变性,
给字符串赋新值时,堆中老值并不消失,而是开辟新空间存储新值,并指向新值。
string s="abcd";
s="cdgf";//堆中abcd不消失,栈中s更新指向堆中新开辟的空间,内有cdgf
故原abcd就没有联系,若大量更改字串,会有大量的原值无联系(内存垃圾)
当程序结束时,GC扫描整个内存,若发现有的空间没有被指向,立即销毁。
string s1="abc";
stirng s2="abc";
Console.ReadKey();//在此处下断点,
运行上面代码,中断后,打开即时窗口,输入&s1回车,显示s1的存储的指针
同时*&s1取得该指针指向堆中的地址。同理输入&s2加车,也可显示上面内容。
可以看到&s1与&s2是不同的,即在栈中两者存储位置不同。
但*&s1与*&s2是相同的,说明存储的是相同的地址(该地址指向同一堆地址)
2.可将字符串看作char类型的一个只读数组.
string s="abcdef";
Console.WriteLine(s[0]);//a
s[1]=a;//错误,不可更改,只读
char[] c=s.ToCharArray;//转为char数组
c[1]=a;//c为aacdef,但是s没有改变
s=new string(c);//s改变,但不是原来存储空间,是新开的堆空间内存
注意:
ToCharArray:将字符串转为char数组。
new string(c):将字符数组char[]转为一个字符串。
三、StringBuilder
using System.Text;
表示可变字符字符串。 此类不能被继承。
不开辟空间,就在原空间更改,所以速度快。
Stopwatch :准确测量运行时间的类。构造函数 new Stopwatch
属性Elapsed :当前总运行时间。返回只读TimeSpan
ElapsedMilliseconds:返回总运行时间(毫秒),只读int64
isRunning:是否运行,返回bool
调用start或StartNew开始运行,Stop或Reset停止。
ElapsedTicks:已用时钟(周期/刻度)数,该数除Frequency得秒数
方法StartNew:初始化新的Stopwatch实例,将运行时间属性设置为零,
然后开始测量运行时间
Stop:停止计时。再Start时会继续计时,Reset才清除以前计时。
ReStart:停止测量,时间清零,重新开始测量运行时间。
Reset: 停止测量,时间清零。
GetTimestamp:获取计时器机制中的当前刻度数.
注意:时钟按周期/刻度进行计数,比如计数4000次,其Frequency表示1秒
中多少次,例如1秒1000次,那么上面时间4000/1000=4秒
静态时间字段Frequency可获只读频率,
StringBuilder创建实例时,会自动创建足够的内存空间来存储字串。
Capacity表示空间的大小,可以创建多少字符。当存储字符大于该容量时会
自动增大内存,增加Capacity。Length是当前字符串的长度。
默认Capacity为16,当需要更多空间时会翻倍。容量也可以人为指定。
但是,若人为指定MaxCapacity后,到达最大上限不会再扩而是引发异常。
构造函数:
StringBuilder() 初始化新实例,字符串值为String.Empty
StringBuilder(int32) 指定Capacity初始化实例
StringBuilder(String) 用指定字符串初始化
StringBuilder(Int32,Int32) 指定起始容量到最大容量
StringBuilder(String,Int32) 指定容量和字符串
StringBuilder(String,Int32,Int32,Int32) 指定子串(前三参数)和容量
value,startIndex,Length,capacity
属性:
capacity:容量,当前实例最大字符数
Length: 长度,当前字符实际长度
MaxCapacity:最大容量,一旦超限引发异常
Chars[]: 读写字符串某位置的字符。由于基于索引实例很大时会非常缓慢。
方法:
Append(byte/int/float/double/char/bool/decimal) 以字符串形式追加
Append(char,Int32) 追加Unicod字符的字符串重复数,后参数repeatCount
Append(char*,Int32) 不符合CLS,用下面替代。
Append(char[],Int32,In32)指定Unicode子数组追加
char[],startIndex,charCount
AppendLine() 将默认的行终止符追加到实例末尾。
AppendLine(String) 追加字串后加入行终止符。
默认的行终止符为Environment.NewLine,即回车换行
Clear:清除实例中所有字符。Length将变成0.
ToString() 将实例转换为String
ToString(Int32,Int32)将实例中子串转换为String。(starIndex,length)
CopyTo(Int32,Char[],Int32,Int32)源字串起始位置开始复制到目标Char指定位置
(int sourceIndex,char[] destination,int desIndex,int count)
Equals(StringBuilder) 是否与指定对象相等,返回bool
Remove(int startIndex,int length) 将指定范围字符移除
Insert(Int32,byte/int/single/double/decimal/char/string)指定位置插入
Insert(int index,string value,int count)将子串一个或多个插入指定位置
Insert(int index,char[] value,int startIndex,int charCount)
将指定Unicode字符的子串插入到指定位置
Replace(char,char)
Replace(string,string)
Replace(char oldChar,char newChar,int startIndex,int length)
将实例中子串范围的老字符,用新字符替换。
Repalce(string oldValue,string newValue,int startIndex,int Length)
同上,用新字串替换老字串
例:string与StringBuilder的效率.107ms VS 3ms 两者用时直接秒杀
string每次都要开辟堆空间浪费时间,StringBuilder不用直接更改即可
StringBuilder sb = new StringBuilder();
string s = "";
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < 10000; i++)
{
s += i;
}
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);//107ms
sw.Restart();
for (int i = 0; i < 10000; i++)
{
sb.Append(i);
}
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);//3ms
注意:一般最终会用ToString(),将StringBuilder转为stringw使用。
一切类型都可用ToString()将其转为字符串类型。
输出你输入字串的长度:
Console.WriteLine("随机输入你心中想到的一个名字:");
//string s = Console.ReadLine();//两者都有Length属性
StringBuilder s = new StringBuilder(Console.ReadLine());
Console.WriteLine("你输入名字的长度是{0}", s.Length);
比较相等:
Console.WriteLine("A输入你喜欢的课程:");
string s1 = Console.ReadLine();//aa
Console.WriteLine("B输入你喜欢的课程:");
string s2 = Console.ReadLine();//aA
if (s1.ToUpper() == s2.ToUpper())//大写只返回副本,并不更改原字串
{ //s1.Equals(s2,StringComparison.OrdinalIgnoreCase);
Console.WriteLine("相同" + s1);//aa
}
else { Console.WriteLine("不相同" + s1); }
Console.WriteLine("C输入你喜欢的课程:");//cc
StringBuilder s3 = new StringBuilder(Console.ReadLine().ToUpper());
Console.WriteLine("D输入你喜欢的课程:");//cC
StringBuilder s4 = new StringBuilder(Console.ReadLine().ToUpper());
if (s3.Equals(s4))
{
Console.WriteLine("相同" + s3.ToString());//CC
}
else
{
Console.WriteLine("不相同" + s4.ToString());//CC
}
splite分割并替换字串:
string s = "a b e_f,,,s'k i*j";
char[] c = { ' ', '_', ',', '*' };
string[] ss = s.Split(c);//替换成""
//删除空串分割:
string[] ss2 = s.Split(c, StringSplitOptions.RemoveEmptyEntries);
string d = "2008-08-01";
string[] dd = d.Split(new char[] { '-' }, StringSplitOptions.RemoveEmptyEntries);
Console.WriteLine("{0,-6}年{1,-5}月{2:0}日", dd[0], dd[1], dd[2]);
四、输出中的复合格式字串
语法:{index[,alignment][:formatString]} 由"索引,对齐:格式字串"组成
index: 索引,由0开始,可多次引用。
alignment: 对齐,由当前位置向后期间位置间,为正右对齐,为负右对齐.
若不设置空白,紧接前面由本身长度决定后方起始位置.
formatString:格式化字串
时间自定义格式:
d 月中某天
dd 月中某天,不足两位,前面为0
ddd 一周中某天缩写,如周五Fri
dddd 一周中某天完整名称,如周五Friday
h 12小时制1-12
hh 12小时制01-12
H 24小时制0-23
HH 24小时制00-23
m 分钟0-59
mm 分钟00-59
M 月份1-12
MM 月份01-12
MMM 月份缩写,六月Jun
MMMM 月份全写,六月June
s 秒0-59
ss 秒00-59
t AM/PM中第一个
tt AM/PM
y 年0-99
yy 年00-99
yyy 年份000-999,最少三位数
yyyy
: 时间分隔 /日期分隔 \转义字符
数字:
0 占位,无该数字/0用0
# 占位,无该数字/0省略
. 小数点
, 三位(千位)分隔
% 数字乘以100,以百分位显示
%。 数字乘以1000,以千分位显示
E+0 结合上面
\
string 原样
; 仅一个,
两个,前面部分用于正值与零,后面用于负值。按最终四舍五入计入
三个,前面用于正值,第二部分用于负值,最后零
12.345 ("#0.0#;(#0.0#);-\0-") -> 12.35 //第一部分
0 ("#0.0#;(#0.0#);-\0-") -> -0- //最后部分
-12.345 ("#0.0#;(#0.0#);-\0-") -> (12.35) //第二部分
12.345 ("#0.0#;(#0.0#)") -> 12.35
0 ("#0.0#;(#0.0#)") -> 0.0
-12.345 ("#0.0#;(#0.0#)") -> (12.35)
五、string
定义:将文本表示为UTF-16代码单元的序列,String继承于Object.
也表示char对象的连续集合,一一对应char的实例,故可用
char数组来表示,唯一区别是String是只读(不可变)
string最多为10亿字符,约2GB
string s1="This is a string“;//直接赋字符串
string s2=@"C:\a\b\c\d\e.txt“;//@取消转义
char[] c={'w','o','r','d'};
string s3=new string(c);//word
string s4=new string('c',4);//cccc
string s5="abc"+"efg";//abcefg
s5+="aa"; //abcefgaa
char a=s5[1];//b 索引从0开始
foreach(char b in s3){s+=b;}//wordword
区别:
Null :string已声明但未分配值,为Null,存储的指针为\0,空指针。
string在栈上空间内值没有指向,堆上没开辟空间,是一个空指针
String.Empty: 即"",已声明且在堆上已开辟空间,但空间内字串长度为0.
WhiteSpace:空白字符,肉眼无法辨别,如:空格 回车换行,Tab等.
unsafe 不安全
大部分C#是可验证的安全代码(由.Net工具可验证代码是否安全),一般安全代码不会
直接使用指针访问内存,也不会分配原始内存而是创建托管对象。
C#支持unsafe,它不一定是危险的,只是安全性由你自己掌握,不由.Net来管理验证。
语法:1.直接在类、方法等前面加入unsafe;
2.直接在代码块中使用unsafe.
public static unsafe void Main()
{//须在项目属性中设置:允许不安全代码,否则报错
char[] c = { 'a', 'b', 'c', '\0', 'A', 'B', 'C', '\0' };
string s = null;
//由长度指定
fixed (char* cPtr = c) { s = new string(cPtr, 0, c.Length); }
foreach (var ch in s) { Console.Write($"{(ushort)ch:x4} "); }
Console.WriteLine();//0061 0062 0063 0000 0041 0042 0043 0000
//不由长度指定,向后找结束符'\0',遇到就结束,若一直无,可能引发访问冲突
fixed (char* cPtr = c) { s = new string(cPtr); }
foreach (var ch in s) { Console.Write($"{(ushort)ch:x4} "); }
//0061 0062 0063
Console.ReadKey();
}
CLS:Common Language Specification公共语言规范
CLR集成了多种语言,若要相互访问,须定义一个相互识别的规范,微软就定义了CLS
不同语言编写的对象就可彼此交互访问。
1、string的构造函数
String(Char*) (不符CLS)初始化指向Unicode字符数组的指定指针指示的值。
String(Char[]) 由指定字符数组初始化.
String(Sbyte*) 由指向8位有符号整数数组的指针指示的值来初始化
String(Char c,int Count) 指定重复次数的Unicode字符来初始化.为0则为Empty
String(Char* value,int startIndex,int length) 指定字符指针数组的范围来初始化
String(Char[] value,int startIndex,int length) 类似上面指定范围初始化
String(Sbyte* value,int startIndex,int length) 类似上面指定范围初始化
String(SByte* value,int startIndex,int length,System.Text.Encodeing enc)
类似上面,指定编码。若enc为null,则为ANSI编码
public static unsafe void Main(string[] args)
{
char[] c = { 'a', 'b', 'c', '\u0000' };
string s;
fixed (char* cPtr = c) { s = new string(cPtr); }
Console.WriteLine(s);//abc
s = new string(c[1], 5);
Console.WriteLine(s);//bbbbb
Console.ReadKey();
}
2、属性
Char[] 字串中某索引的char值
length 字串的长度
string s = "abc";
Console.WriteLine($"{s[0]},{s.Length}");//a,3
3、String运算符
== 是否相等,
!= 是否不相等
+ 连接,只要有一个是字串,按连接处理
string s1 = "abc", s2 = new string(new char[] { 'A', 'B', 'C' });
Console.WriteLine("{0},{1}", string.Equals(s1, s2), s1 != s2);
4、换行
在字串输出中,可用转义符\n表示换行。
在代码输出中,只要不遇见分号或语块结束,默认是连续的。对字串可截取一部分回车后,
在下一行中用+,另起剩下的字串。
对逻辑符,可对逻辑表达式回车后,以运算符另起逻辑表达式
Console.WriteLine("abc\nABC");//两行输出
string s = "abc" +
"ABC";//字串另起
if (s == "" &&
s != string.Empty) //逻辑另起
{ Console.WriteLine(s); }
5、方法
1)拆分
split(string[] separator,int count,StringSplitOptions options)
用指定分隔字串和可选项拆分为最大数量的子字串。
public static void Main(string[] args)
{
string s1 = ",ONE,,TWO,,,THREE,,";
string s2 = "[stop]ONE[stop][stop]TWO[stop][stop][stop]THREE[stop][stop]";
char[] charSeparators = new char[] { ',' };
string[] stringSeparators = new string[] { "[stop]" };
string[] result;
Show(s1.Split(charSeparators, StringSplitOptions.None));
//.ONE..TWO...THREE... 用字符数组分隔,9个元素,null保留
Show(s1.Split(charSeparators, StringSplitOptions.RemoveEmptyEntries));
//ONE.TWO.THREE. 3个元素,null剔除
Show(s2.Split(stringSeparators, StringSplitOptions.None));
//.ONE..TWO...THREE... 用字串数组分隔,9个元素,null保留
Show(s2.Split(stringSeparators, StringSplitOptions.RemoveEmptyEntries));
//ONE.TWO.THREE. 3个元素,null剔除
Show(s2.Split(stringSeparators, 2, StringSplitOptions.None));
//.ONE[stop][stop]TWO[stop][stop][stop]THREE[stop][stop]. 2个元素,第一个空
Show(s2.Split(stringSeparators, 2, StringSplitOptions.RemoveEmptyEntries));
//ONE.TWO[stop][stop][stop]THREE[stop][stop]. 2个元素,剔除null
Show(s2.Split(stringSeparators, 7, StringSplitOptions.RemoveEmptyEntries));
//ONE.TWO.THREE. 超个本身仍按本身最多元素算,3个元素,剔除null
Console.ReadKey();
}
public static void Show(string[] strings)
{
foreach (string s in strings) { Console.Write(s + "."); }
Console.WriteLine();
}
注:split方法忽略分割符为null和""的情况。
匹配规则:实例中遇到的子串优于分割元素的顺序。
即实例从头开始向后取子串,分割符从索引0开始匹配,不符合,索引增加;
符合继续子串后扩,直到完全匹配。
1.字串"abcdef",分割符{"ef","bcde"},结果{"a","f"}
后扩至abcde时,分割索引0不匹配,增加索引为1即bcde,匹配。结果a与f.
2.上例分割符为{"bcd","bc"},结果{"a","def"}
扩至ab时,索引0有b相同(索引1排不上号),继续abc,索引0仍有相同(索引1
仍然排不上号),继续abcd时,索引0完全匹配,结果a与ef
3.上例分割符为{"bc","bcd"},结果{"a","def"}
扩至ab,索引0有b相同(同理索引1吃灰),扩至abc时,索引0完全匹配,结果
为a和def。
4.上例分割符{"cd","c","bce"},结果{"ab","ef"}
扩至ab时,索引0与1吃灰,索引2有b上位,继续后扩abcd,索引2不符。回头
继续用索引0与1,两者都上位,但索引前位0优先,cd匹配,结果ab与ef
5.上例分割符{"c","cd","bce"},结果{"ab","def"}
继4分析,到abcd时,索引2吃灰,返回索引0上位,符合,结果ab与def
6.上例分割符{"d","cde","b","bcdd"} 结果为a,null,f
到ab时,索引2上位,匹配,分成a与cdef;继续匹配(a就不分析了),cdef从头
开始,c时只有索引1上位,继续cd,索引1仍然上位(子串优先索引所以索引0只
能干看),cde时索引1完全匹配,于是结果是a,null,f. 共三个元素。
总结:子串先上位则占位,不符时,再索引依次占位。索引优先级最低。
只要有符合部分,哪怕后面的索引也将占位.
public static void Main(string[] args)
{
string s = "abcdef";
string[] separator1 = { "b", "bcd" };//1
string[] separator2 = { "bcd", "b" };//2
string[] separator3 = { "bc", "bcd" };//3
string[] separator4 = { "bcde", "bc" };//4
string[] separator5 = { "d", "bcd" };//5
string[] separator6 = { "bcd", "d" };//6
string[] separator7 = { "c", "cd", "bce" };//7
string[] separator8 = { "d", "cde", "bcdd", "b" };//8
Console.WriteLine("------------1-2");
Show(s.Split(separator1, StringSplitOptions.None));//a^cdef^2
Show(s.Split(separator2, StringSplitOptions.None));//a^ef^2
Console.WriteLine("------------3-4");
Show(s.Split(separator3, StringSplitOptions.None));//a^def^2
Show(s.Split(separator4, StringSplitOptions.None));//a^f^2
Console.WriteLine("------------5-6");
Show(s.Split(separator5, StringSplitOptions.None));//a^ef^2
Show(s.Split(separator6, StringSplitOptions.None));//a^ef^2
Console.WriteLine("------------7-8");
Show(s.Split(separator7, StringSplitOptions.None));//ab^def^2
Show(s.Split(separator8, StringSplitOptions.None));//a^^f^3
Console.ReadKey();
}
public static void Show(string[] strings)
{
foreach (string s in strings) { Console.Write(s + "^"); }
Console.WriteLine(strings.Length);
}
split(char[] separator,int count,StringSplitOptions options)
用指定分隔字符和可选项拆分最大数量count的子字符串
split(string[] separator,StringSplitOptions options)
split(char[] separator,StringSplitOptions options)
split(params char[] separator) 用指定分隔字符拆分
2)大小写副本
ToUpper() 返回字串转为大写的副本
ToLower() ............小........
3)判断开始或结尾
StartsWith(string value) 判断开始是否为指定字串,返回bool
EndsWith(string value) ....结尾..........
StartsWith(string value,StringComparison comparisonType)
判断开始,选项忽略大小写用得多OrdinallgnoreCase
EndsWith(string value,StringComparison comparisonType)
判断结尾,选项忽略大小写用得多OrdinallgnoreCase
4)删除前后匹配符
Trim() 删除前后空白符
TrimEnd() 删除末尾空白符
TimeStart() ....开始.....
Trim(parms char[] trimChars) 删除前后指定字符
TrimEnd(parms char[] trimChars) ....结尾..
TrimStart(parms char[] trimChars) ....开始..
5)子串,转换
Substring(int startIndex) 指定位置到字串末尾(索引从0开始)索引大于长度或小于零异常
Substring(int startIndex,int length) 指定位置开始到指定长度
string s="abcdef";
s.Substring(2);//cdef
s.Substring(2,2);//cd
ToCharArray() 将此实例的字符串复制到Unicode字符数组。返回Char[]
逆方法:若字符数组->字串:用构造函数String(Char[])
ToCharArray(int startIndex,int length) 类上,指定起始和长度复制到Char[]
string s="abcdef";
char[] c=s.ToCharArray();//{'a','b','c','d','e','f'}
char[] c1=s.ToCharArray(4,2);//{'e','f'}
ToString() 转换为String,不执行实际转换。引用类型一般返回类型
int a = 3; double b = 2.3;
Stopwatch sw = new Stopwatch();
Console.WriteLine($"{a.ToString()},{b.ToString()},{sw.ToString()}");
//3,2.3,System.Diagnostics.Stopwatch 上面转换可省,会自动转string
6)替换
Replace(char oldChar,char newChar) 用新字符替换老字符,返回一新string
Replace(string oldValue,string newValue) 用新串替换老串,返回一新串
注:返回是新串,原串未发生改变;区分大小写。可连续调用链接一起,实现多次替换
string s = "abcdef";
string s1 = s.Replace('a', 'b').Replace('d', 'w');//bbcwef
string s2 = s.Replace("d", "e").Replace("f", "g");//abceeg
7)删除
Remove(int startIndex,int count) 删除从起始到指定长度的字串,返回新串,原串未变.
Remove(int startIndex) 删除从起始到末尾的字串。
string s = "abcdef";
string s1 = s.Remove(2);//ab
string s2 = s.Remove(2, 2);//abef
8)填充
PadLeft(int totalWidth) 左侧填充空格,使新串总长为totalWidth,实现右对齐
PadLeft(int totalWidth,char paddingChar) 左侧用指定字符填充,实现右对齐
PadRight(int taotalWidth) 右侧填充空格.............................左对齐
PadRight(int totalWidth,char paddingChar) 右侧...
string s = "ab";
string s1 = s.PadLeft(5); // ab
string s2 = s.PadLeft(5, 'z');//zzzab
string s3 = s.PadRight(5); //ab
9)查找索引
IndexOf(string value,int startIndex,int count,StringComparison comparisonType)
value要搜索的字串,startIndex搜索起始位置,count起始往后长度,末参是否区别大小
IndexOf(string value,int startIndex,StringComparison comparisonType)
搜索起始到末尾
IndexOf(string value,int startIndex,int count) 指定起始、位置
IndexOf(char value,int startIdex,int count)
IndexOf(string value,StringComparison comparisonType) 是否区分大小写(字符不需要)
IndexOf(string value,int startIdex) 指定起始到末尾
IndexOf(char value,int starIdex)
IndexOf(string value) 搜索整个
IndexOf(char value)
string s = "abAbefgta"; int n;
n = s.IndexOf("a", 1, 2, StringComparison.OrdinalIgnoreCase);//2
n = s.IndexOf("a", 1, 2, StringComparison.Ordinal);//-1
n = s.IndexOf('a', 4, 2);//-1
n = s.IndexOf('a', 4, 5);//8 5改成6时会异常,索引超限
类似上面是找第一个匹配项,下面是搜索最后一个匹配项.
LastIndexOf(string value,int startIdex,int count,StringComparison comparisonType)
count是从startIndex从右往左的字符数,超限会异常
LastIndexOf(string value,int startIndex,Stringcomparison comparisonType)
指定起始从右往左到起始
LastIndexOf(string value,int startIndex,int count)
LastIndexOf(char value,int startIndex,int count)
LastIndexOf(string value,int startIndex)
LastIndexOf(char value,int startIdex)
LastIndexOf(string value)
LastIndexOf(char value)
LastIndexOf(string vlaue,StringComparison comparisonType)
string s = "abAabefagta"; int n = 0;
//"a",1,3 时会异常,起始索引1从右往左3个字符超出数组限制
n = s.LastIndexOf("a", 3, 3, StringComparison.OrdinalIgnoreCase);//3
n = s.LastIndexOf("A", 3, 3, StringComparison.Ordinal);//2
n = s.LastIndexOf('a', 10, 4);//10
n = s.LastIndexOf('a', 9);//7
n = s.LastIndexOf("a");//10
=========多个查找,多个字符数组去查找,返回第一个匹配项
IndexOfAyn(char[] anyof,int startIndex,int count) 指定起始、位置
IndexOfAny(char[] anyof,int startIndex)
IndexOfAny(char[] anyof) anyof数组中只要有一个匹配立即返回当前索引
LastIndexOfAny(char[] anyof,int startIndex,int count)
LastIndexOfAny(char[] anyof,int startIndex)
LastIndexOfAny(char[] anyof)
string s = "abcdeef";
char[] c = { 'e', 'f', 'c' };
Console.WriteLine(s.IndexOfAny(c));//2 其中c先匹配
//4改成3,会因5向字串前面位置超限引发异常
Console.WriteLine(s.LastIndexOfAny(c, 4, 5));//2 e先匹配
10)分割式连接
String.Join(string separator,System.collection.Generic.IEnumerable<string> values)
串连集合values各成员,仅在成员间用指定分隔符
String.Join(string separator,params object[] values) 所有元素
String.Join(string separator,params string[] value)
String.Join(string separator,string[] value,int startIndex,int count) 指定元素
String.Join<T>(string separator,System.Collections.Generic.IEnumerable<t> values)
string[] s = { "a", "b", "c", "d" };
List<int> lst = new List<int>() { 1, 2, 3, 4 };
//注意是成员之间,首部与末尾都没有分割符^
Console.WriteLine(string.Join("^", s));//a^b^c^d
Console.WriteLine(string.Join("^", lst));//1^2^3^ 4
Console.WriteLine(string.Join("^", 'a', 'b', 'c'));//a^b^c
Console.WriteLine(string.Join("^", s, 1, 2));//b^c
注意:1.被连接成员会隐式转为字符串;
2.若连接第一个成员为null时,将不会连接各成员。第一元素应处理成Empty方可执行;
3.若分隔符为null或除第一元素外其余为null,将以String.Empty代替。
11)连接(+)
String.Concat(System.Collections.Generic.IEnumerable<string> values)
各成员串联(不加分隔符),若成员为null则视为String.Empty处理
String.Concat(string str0,string str1,string str2,string str3) 四个相加
String.Concat(string str0,string str1,string str2) 三个相加
String.Concat(string str0,string str1)
String.Concat(object arg0,object arg1,object arg2,object arg3) 隐式转换成string相连
String.Concat(object arg0,object arg1,object arg2)
String.Concat(object arg0,object arg1)
String.Concat(params string[] values) 成员有null时自动用String.Empty替换
String.Concat(params object[] args)
String.Concat<T>(System.Collections.Generic.IEnumerable<T> values) 成员相连
String.Concat(object arg0) 实际调用ToString()
12)是否相等bool
Equals(string value,StringComparison comparisonType) 是否相等,返回bool、
String.Equals(string a,string b,StringComparison comparisonType)
String.Equals(string a,string b)
Equals(object obj) obj隐式可转字串
Equals(string value)
13)插入
Insert(int startIndex,string value) 指定索引位置插入指定字串,返回新字串.
指定索引最大可为原索引+1
string s = "abcd";
Console.WriteLine(s.Insert(3, "z"));//abczd
Console.WriteLine(s.Insert(4, "z"));//abcdz 4改5异常
14)拘留池(暂存池、缓冲池、暂存池)the intern pool
因为字符串是不可变的,所以CLR(CLR是公共语言运行时,Common Language Runtime)可能会
将相同值的字符串用同一个实例。程序中大量使用字符串,有不少是重复性的,为了降低内存
占用,.Net将代码中声明的字符串放到字符串拘留池中,值相同的字符串共享同一个实例。字
符串是不变的。不是所有字符串都在拘留池中,.Net会判断哪些该放。
通用语言运行时通过维护一个被称为拘留池的表来节约字符串的存储,该表包含对程序中
以编程方式声明或创建的每个独特字面字符串的单一引用。因此,一个具有特定值的字面字
符串的实例在系统中只存在一次。故多个字面字符串会指向同一实例以节约内存。
当给一个变量分配字符串的时候,CLR先到驻留池里找,如果找到了,就将该字符串的引用
给这个变量,如果没有,就将该字符串创建到驻留池里,然后在将引用给该变量。
动态字符串默认是不在字符串拘留池中的。
string s1 = "拘留池", s2 = "拘留池";
Console.WriteLine("{0},{1}", s1 == s2, ReferenceEquals(s1, s2));//T T
string s3 = "abc", s4 = new string(s3.ToCharArray());
Console.WriteLine("{0},{1}", s3 == s4, ReferenceEquals(s3, s4));//T F
string s5 = "abc", s6 = "ab" + "c";//字面符,为静态,进入拘留池查找
Console.WriteLine("{0},{1}", s5 == s6, ReferenceEquals(s5, s6));//T T
//string s7 = Console.ReadLine();//输入abc 为动态不进入拘留池
//Console.WriteLine("{0},{1}", s5 == s7, ReferenceEquals(s5, s7));//T F
string s8 = new string("abc".ToCharArray());
Console.WriteLine("{0},{1}", s5 == s8, ReferenceEquals(s5, s8));//T F
string s9 = (new StringBuilder("abc")).ToString();
Console.WriteLine("{0},{1}", s5 == s9, ReferenceEquals(s5, s9));//T F
string a = "a", b = "b", c = "c", d = a + b + c;//d产生了ab与abc两个
//+连接是新开辟空间,所以地址是不一样的
Console.WriteLine("{0},{1}", s5 == d, ReferenceEquals(s5, d));//T F
15)添加拘留池
String.Intern(string str) 在拘留池搜索str,若有返回引用,若无添加入池再返回引用
String.IsIntern(string str) 检测str是否在池,在返回引用,无返回null.
string s1 = "MyTest";
string s2 = new StringBuilder().Append("My").Append("Test").ToString();
string s3 = string.Intern(s1);//检测s1,入池并返回引用. s1与s3同引用
Console.WriteLine(ReferenceEquals(s1, s2));//False
Console.WriteLine(ReferenceEquals(s1, s3));//True
16)GetEnumerator取得
CharEnumerator GetEnumerator() String.GetEnumerator由字串构造字符枚举器
string s = "The Example Of String.GetEnumerator";
CharEnumerator ce = s.GetEnumerator(); //取得字符枚举器对象
while (ce.MoveNext())//索引起始位于第一个之前,移动成功True
{//索引若超出最后一个字符,则不会更改索引,移动失败返回false
if (char.IsUpper(ce.Current)) Console.Write(ce.Current);
else Console.Write(char.ToUpper(ce.Current));
}
THE EXAMPLE OF STRING.GETENUMERATOR
17)字串比较
String.Compare(string strA,int indexA,string strB,int indexB,int length,
System.Globlization.CultureInfo culture,
System.Globlization.CompareOptions options)
字串strA与strB分别从各自的起始位置开始比较长度间字符。
culture为指定区域,若为null则使用当前区域。
CompareOptions指定比较项,如忽略大小写,符号
返回:<0,strA在strB前;0,相同或length=0;>0,strA在strB之后.
String.Compare(string strA,int indexA,string strB,int indexB,int length,
bool ignoreCase,
System.Globalization.CultureInfo culture)
String.Compare(string strA,int indexA,string strB,int indexB,int length,
StringComparison comparisonType)
String.Compare(string strA,int indexA,string strB,int indexB,int length,
bool ignoreCase)
String.Compare(string strA,int indexA,string strB,int indexB,int length)
String.Compare(string strA,string strB,
System.Globalization.CultureInfo culture,
System.Globalization.CompareOptions options)
String.Compare(string strA,string strB,bool ignorCase,
System.Globalization.CultureInfo culture)
String.Compare(string strA,string strB,StringComparision comparsionType)
String.Compare(string strA,string strB,bool ignoreCase)
String.Compare(string strA,string strB)
string s1 = "Jack Smith", s2 = "JAcn Doe";
CompareOptions co=CompareOptoins.IgnoreCase;
string.Compare(s1, 0, s2, 0, 1, new CultureInfo("en-Us"), co);//0
string.Compare(s1, 0, s2, 0, 2, new CultureInfo("en-Us"), co);//0
string.Compare(s1, 0, s2, 0, 3, new CultureInfo("en-Us"), co);//0
string.Compare(s1, 0, s2, 0, 4, new CultureInfo("en-Us"), co);//-1
string a = "hello";
string b = "h";
b += "ello";
Console.WriteLine(a == b);//true 值是否相等
Console.WriteLine(string.ReferenceEquals(a, b));
//false 实例是否相同
string s = "abdicdkadkeaekda";
int index = 0, index1 = 0;
while (index != -1)
{
index = s.IndexOf("a", index1);
if (index >= 0)
{
Console.WriteLine(index);
index1 = index + 1;
}
}
string p = @"C:\a\b\c\d\e\f\abc.mp3";
int index = p.LastIndexOf("\\");//最后一个\
Console.WriteLine(p.Substring(index + 1));
Console.ReadKey();//取文件名
string[] s = { "我", "们", "是", "中", "国", "人" };
string sNew = string.Join("|", s);
Console.WriteLine(sNew);//我|们|是|中|国|人
string s = "abc";
char[] c = s.ToCharArray();
Array.Reverse(c);
s = new string(c);
Console.WriteLine(s);
Console.WriteLine("输入一段英文句子:");
string s = Console.ReadLine();
string[] s1 = s.Split(new char[] { ' ', '.', ',' }, StringSplitOptions.RemoveEmptyEntries);
Array.Reverse(s1);
Console.WriteLine(string.Join(" ", s1));
string s = "abc@163.com";
int index = s.IndexOf('@');
Console.WriteLine(s.Substring(0, index - 1));
Console.WriteLine(s.Substring(index + 1));
六、指针
指针类型声明:
type* identifier;
void* identifier;//允许,但不推荐。因未说明具体指针类型
int* p1,p2,p3;//正确,三个指针
int *p1,p2,p3;//错误,只能按语法int*
指针不能用于引用类型,一般用于值类型
int* p;//指向整数的指针--------*p表示由int中指针找到指向的值
int** p;//指向整数的指针的指针
int*[] p;//指向整数的指数的一维数组
char* p;//指向字符的指针
void* p;//指向未知类型的指针
指针运算:
* 执行指针间寻址 a=*&a
-> 通过指针访问结构的成员. x->y等同(*x).y
[] 为指针建立索引
& 获取变量的地址
++和-- 递增/减指针
+/- 执行指针算法
==,!=,>,>=,<,<= 比较指针
stackalloc 在堆栈上分配内存
fixed语句
防止GC重新定位可移动变量,并声明指向该变量的指针。固定变量的地址在语句的
持续时间内不会更改。
只能在相应的fixed语句中使用声明的指针。声明的指针是只读,不可修改。
只能在unsafe上下文中使用fixed语句。
fixed保证GC在语句主体执行期间不会重新定位或释放包含对象实例。
unsafe
{
int[] n = { 10, 20, 30 };
int* p;
fixed (int* first = &n[0], last = &n[2])
{//连续8字节,即2个int32(4字节)
Console.WriteLine((int)last - (int)first);//8
p = first + 1;//指针移动1个int,即4位,指向n[1]
Console.WriteLine(*last - *p);//10
}//fixed内定义的指针不可更改
}
七、继承
开发中,每一个类应单独写在一个文件中,不能混合.
把多个类中重复的成员封装成单独的一个类,作为这些类的父类或基类,以解决代码冗余。
这几类称为父类的子类或派生类。
子类继承于父类public的属性与方法。不继续私有成员private.
C#中,所有类直接或间接继承了object类。若没写继承,那它就继承object。
子类有没有继承父类的构造函数????
子类不能继承父类的构造函数。但是,父类必须要有无参的构造函数,因为子类构造之前
先要构造父类(即创建子类对象之前,其内部先要创建一个父类对象,以便子类继承它的成员)
当父类创建有参构造函数后,无参构造函数消失。子类默认调用父类的无参函数来创建父
类对象,以便子类继承父类中的成员。此时,若父类消失了无参构造函数,会引发子类错误。
解决办法:
1)在父类中手动重新写一个无参的构造函数,以便子类调用。
2)在子类的构造函数中显式调用父类的构造函数。
在子类构造函数的后面用:base(参数表) 来调用父类的构造函数
八、继承的特性
1.继承的单根性:一个子类只能有一个父类(基类)。
2.继承的传递性:
九、New关键字
1)创建新对象;
2)隐藏从父类那里继承过来的成员。
若子类有成员与父类成员相同,子类会隐藏父类的这个成员,即只能调用同名的子类成员。
此时vs会提示警告,若是故意隐藏,添加new表示意图后,警告消失。
public class Person //基类
{
private string _name; private int _age; private char _gender;
public string Name
{ get { return _name; } set { _name = value; } }
public int Age
{ get { return _age; } set { _age = value; } }
public char Gender
{ get { return _gender; } set { _gender = value; } }
public Person(string name, int age, char gender)
{ Name = name; Age = age; Gender = gender; }
public void SayHello()
{ Console.WriteLine("基类同名时,被子类隐藏"); }
}
public class Student : Person //继承
{
private double _worktime;
public double Worktime
{ get { return _worktime; } set { _worktime = value; } }
public Student(double worktime, string name, int age, char gender) : base(name, age, gender)
{ Worktime = worktime; }//用base调用基类构造函数
public new void SayHello() //不加new不出错,但会有警告
{ Console.WriteLine("我叫{0},我年龄是{1},我是一名{2}生,工作年限{3}。", Name, Age, Gender, Worktime); }
}
根据上面,Studendt继承于Person:
Student s = new Student(3, "孙全", 33, '男');
s.SayHello();