C#基础
Write 输出字符串
WriteLine输出字符串最后加回车
Write(Line)重载了18个函数,适应各种输出,比如WriteLine(4)就直接输出4 重载时unicode码自动加了18,变成了4对应的unicode码
Console.Read();//读一个字符
Console.ReadKey(false);//读一个字符且显示用户输入的字符,true则不显示(任意键继续),不加参数为true
Console.ReadLine();//读一行字符串
Readonly运行时常量(const) 可弥补const无法定义复杂类型常量的缺点,比如自定义的类就是复杂类型
交错数组:每行的列数可以不一样的多维数组
//交错数组
int [][] interArray = newint [2][];//表示有两行
interArray[0]= new int[2]{0,1};//第0行有两个格子
interArray[1]= new int[3]{2,3,4};//第1行有三个格子
interArray[1][0]= 2;
//C#的数组也没法在初始化以后整行赋值,让我感到很遗憾
//输出
Console.WriteLine(interArray[0][0].ToString()+","+interArray[0][1].ToString());
Console.WriteLine(interArray[1][0].ToString() + "," +interArray[1][1].ToString()+","+interArray[1][2].ToString());
C#的string关键词映射到.NET类库的String(大小写不一样,C#严格区分大小写,不过这两个是一样的效果)。用法跟MFC的CString和STL的string差不多,不过比这俩多一些功能,比如排序什么的。
String是引用类型,但其值确是不可变的,即是指已经赋值就不能再改变。针对字符串的一些操作(如合并、截取)都会产生出新的String对象。
由于写复制的特性,在一些需要大量合并字符串的场合就会产生出很多临时性的String对象,然后又被丢弃,浪费掉不少内存。所以类库中有另一个System.Text.StringBuilder类型来高效的拼接字符串。
但是StringBuilder没有重载+运算符,只能通过.Append函数来追加。不太方便。
另一个办法就是用string.ToCharArray()把string转成字符串,处理完后用new string(char[])带参构造来新建一个新的string。
String数组名的length方法返回的是有几个格子。
C#的进制转换
int intTest = 5;
Console.WriteLine(intTest.ToString()+"="+Convert.ToString(intTest,2));//2为进制基数
委托:
委托类似于C/C++里的函数指针,但是它是实际上是一个对象.
声明一个委托类,声明参数表和返回值类型。
定义对象,参数里是委托函数的函数名,委托函数的参数表和返回值必须与委托对象的声明一致。
调用委托对象(参数表)即调用委托函数。
委托链:
C#的委托链重载了+和-,指向不同或相同函数的委托对象可以通过+连成委托链,
比如下例中我把d += d2,这样在后面调用d()的时候会接着调用d2的委托函数。
也就是会执行整个委托链上的函数,如果有返回值则是得到最后一个节点的返回值(这也是符合从头到尾执行的流程的,后面的返回值把前面的覆盖了,相当于多次赋值)
//委托与委托链
delegateTest d = newdelegateTest(dlgtTest);//定义委托类delegateTest对象
delegateTest d2 = newdelegateTest(dlgtTest2);
d+= d2;//链上dlgtTest2
d+= new delegateTest(dlgtTest3);//链上dlgtTest3
Console.WriteLine("委托1+2+3");
d(1);
Console.WriteLine();
Console.WriteLine("委托1+3");
d-= d2;
d(1);
Console.WriteLine();
Console.WriteLine("委托1+3+2+2");
d+= d2;
d+= d2;
d(1);
Console.WriteLine();
delegate void delegateTest(doublex);//声明一个委托类delegate,并定义参数表和返回值
static void dlgtTest(double x)
{
Console.Write("委托1");
}
static voiddlgtTest2(double x)
{
Console.Write("委托2");
}
static voiddlgtTest3(double x)
{
Console.Write("委托3");
}
输出结果
事件:
事件我觉得是C#里的一个消息响应模型,用上它可以把消息接收和响应分开,事件作为一个任务中转站,使结构更清晰。
namespaceCalculator_with_CSharp
{
class Program
{
static void Main(string[] args)
{
CCalculator calculatorObj = new CCalculator();
Console.WriteLine("2-1结果为:");
Console.WriteLine(calculatorObj.GetResult(2,1,'-'));
}
}
public class CCalculator//计算器类
{
public delegate double operatorDelegate(double num1, doublenum2);//基础运算委托
public delegate double calDelegate(double num1, doublenum2, char operatorType);//计算委托
public event calDelegate calRecieverEvent;//计算事件
public CCalculator()
{
calRecieverEvent+=new calDelegate(GetResult);//把GetResult方法绑定到计算事件
}
double Cal(doublenum1, double num2,charoperatorType)
{
if (calRecieverEvent != null)
{
return calRecieverEvent(num1, num2, operatorType);//触发事件
}
else
{
return double.MaxValue;
}
}
public doubleGetResult(double num1, doublenum2,char operatorType)
{
operatorDelegate opeDelegate;
switch (operatorType)
{
case '+':
opeDelegate= new operatorDelegate(Add);break;
case '-':
opeDelegate= new operatorDelegate(Minus);break;
case '*':
opeDelegate= new operatorDelegate(Mlt);break;
case '/':
opeDelegate= new operatorDelegate(Div);break;
default:
return double.MaxValue;
}
return opeDelegate(num1, num2);
}
//基础运算函数
double Add(doublenum1, double num2) { returnnum1 + num2; }
double Minus(doublenum1, double num2) { returnnum1 - num2; }
double Mlt(doublenum1, double num2) { returnnum1 * num2; }
double Div(doublenum1, double num2) { if(num2 == 0) return double.MaxValue;else returnnum1 / num2; }
}
}
枚举的好处:
之前一直觉得枚举除了占空间小没什么优点,今天看了C#的书才发现,还有些别的优点。
枚举可以让程序可读性更强,比如我们需要使用现实中的一个序列,比如星期,月份,但是直接用数字没法看出其意义,但是要用变量的话就得定义七个(如果是星期)显得比较乱,这时候如果用枚举,把每个星期几都放进一个Days的枚举类型,用的时候如果是礼拜一就是Days.Monday,非常直观,而且整个枚举只占一个int型的空间,而不是7个。
同时枚举的值是不可改变的,这样带来的好处就是更安全,编程一大原则就是宁可在编译时出错也不要在运行时出错。
//枚举
Days today = Days.Friday;
// Days.Friday = 1; //错误,不可变
// Days.Friday = Days.Monday; //错误,内部也不可变
// today = Days.Sixday; //错误,限定了取值范围
today= (Days)20;
Console.WriteLine((int)today);
}
enum Days {Monday= 1,Tuesday,Wednesday = Monday +2,Thursday,Friday,Saturday,Sunday};
Foreach循环
foreach是对一个集合或者数组进行的循环
//foreach
int[] each = { 1, 2, 3, 4, 5 };
int sum = 0;
foreach (int j in each)
{
sum+= j;
}
Console.WriteLine(sum); //输出显示15
每次foreach循环结束j会自动指向each中的下一个元素,直到读完,不用考虑循环次数、越界,且代码简洁。
C#的函数重载与返回值无关。
String的分割
C#中string的Split跟C语言中的strtok差不多,不过更好用,返回的是一个string数组,每个格子是一个分割结果,第一个参数也可以是string。
//string分割
string strSplit = "1,23;";
char [] separator = ",;".ToCharArray();
foreach (string temp in strSplit.Split(separator,StringSplitOptions.RemoveEmptyEntries))
//不加后面的参数可能会出现多余的空格,该参数是移除结果中多余的空格用的
{
Console.WriteLine(temp);//输出1 2 3
}
Params关键词
我个人觉得params用法方便在于如下的,不同类型对象的处理,参数表直接放各种类型。
//params
int[] paramsTestInt = { 1, 2, 3 };
Display(1,1,'d',"dfa",paramsTestInt[2]);
object[] objArrayTest ={ 1, 'd', "dfafd"}; //此处可见实际上上面的Display是把
Display(objArrayTest); //参数表中的东西转换成了一个对象数组
}
//params用
public static void Display(params object[] a)
{
foreach (object j in a)
{
Console.WriteLine(j);
}
}
Ref关键词
Ref即C#的引用,跟C++的引用一个意思。
声明函数时在类型前加ref,调用函数时也要加ref。
Out关键词
与ref功能一样,区别在于ref用前需要初始化,而out只需要声明。
Out关键词可以理解为,向外传参。
C#类成员
字段(变量)、方法(函数)、属性
属性是特殊的方法,用于给私有成员做接口,里面有set和get关键词。
//属性
CProp cprop = new CProp();
cprop.A= 2; //A的set被调用
Console.WriteLine(cprop.A); //A的get被调用
}
//属性用
public class CProp
{
private int a; //习惯上字段用小写,其属性同名开头并大写
public int A{set;get;}
}
其实set和get应该是这样的:相当于函数里面套了函数,不过.NET3.x以上就简化了。
public int A
{
set
{
a= value;
}
get
{
return a;
}
}