C#程序结构:
C#程序是以
在文件头声明要使用的库或其他程序。
using System;
下面定义命名空间,命名空间中定义类,再者是主程序,主程序必须是main函数,否则报错。
using System;
namespace HelloWorldApplication
{
class HelloWorld
{
static void Main(string[] args)
{
/* 我的第一个 C# 程序*/
Console.WriteLine("Hello World");
Console.ReadKey();
}
}
}
一个命名空间中可以存在多个类
在创建变量时可以修饰其隐私类型
修饰后可防止其他程序的错误引用。
方法的创建(函数)
定义完成后,我们可以根据当前方法的可访问 类型,来在程序适当的地方来调用。
using System;
namespace CalculatorApplication
{
class NumberManipulator
{ //创建一个类,其他处可引用
public int FindMax(int num1, int num2)
{ //在类中创建一个方法
/* 局部变量声明 */
int result;
if (num1 > num2)
result = num1;
else
result = num2;
return result;
}
static void Main(string[] args)
{
/* 局部变量定义 */
int a = 100;
int b = 200;
int ret;
//在此处声明一个存储器,它叫n,并赋给他一个实例化的类,即上方已创建的类
NumberManipulator n = new NumberManipulator();
//调用 FindMax 方法
ret = n.FindMax(a, b); //此处就是创建的n类,并使用他的其中一个方法
Console.WriteLine("最大值是: {0}", ret );
Console.ReadLine();
}
}
}
递归
定义的方法可以调用本身,称之为递归,使用需要一定的逻辑
using System;
namespace CalculatorApplication
{
class NumberManipulator
{
public int factorial(int num)
{
/* 局部变量定义 */
int result;
if (num == 1)
{
return 1;
}
else
{
result = factorial(num - 1) * num;
return result;
}
}
static void Main(string[] args)
{
NumberManipulator n = new NumberManipulator();
//调用 factorial 方法
Console.WriteLine("6 的阶乘是: {0}", n.factorial(6));
Console.WriteLine("7 的阶乘是: {0}", n.factorial(7));
Console.WriteLine("8 的阶乘是: {0}", n.factorial(8));
Console.ReadLine();
}
}
}
理解方法详情见本人另一篇文章:递归理解思路
将结果直接输出到输入变量
如果我想将一个变量A进行放大10倍在赋值给变量A,我可以
A = 放大方法(A);
还可以写成以下的方式 ,在调用getvalue方法后传进去的变量就得到了计算后的结果。
using System;
namespace CalculatorApplication
{
class NumberManipulator
{
public void getValue(out int x )
{
int temp = 5;
x = temp;
}
static void Main(string[] args)
{
NumberManipulator n = new NumberManipulator();
/* 局部变量定义 */
int a = 100;
Console.WriteLine("在方法调用之前,a 的值: {0}", a);
/* 调用函数来获取值 */
n.getValue(out a);
Console.WriteLine("在方法调用之后,a 的值: {0}", a);
Console.ReadLine();
}
}
}
在方法调用之前,a 的值: 100
在方法调用之后,a 的值: 5
当然,输入参数也可以是,none ,但是要在方法内将他赋值。
Null
在我们来存储一些数据时,部分数据会有为空的情况,在程序中直接去读,会提示变量未被赋值无法使用,我们可以通过一下方法来将变量赋空值。
using System;
namespace CalculatorApplication
{
class NullablesAtShow
{
static void Main(string[] args)
{
int? num1 = null;
int? num2 = 45;
double? num3 = new double?();
double? num4 = 3.14157;
bool? boolval = new bool?();
// 显示值
Console.WriteLine("显示可空类型的值: {0}, {1}, {2}, {3}",
num1, num2, num3, num4);
Console.WriteLine("一个可空的布尔值: {0}", boolval);
Console.ReadLine();
}
}
}
在我们在进行赋值时,如果担心数据源为null,我们可以加一个替代值,如果前者为null,则返回替代值。
数组、类、方法的创建及调用
数组
datatype[] arrayname = new datatype[指定数组长度] {赋值,也可以不赋值,也可以把一个数组赋值给另一个数组}
使用
arrayname[数组地址] = 要赋的值
类
classtype classname = new classtype()
使用
n.方法()
即使在类内使用也要创建一个类。
struct
自定义结构体数据类型,可以称之为复杂数据类型,如果我们要存储用户的各种类型的信息,我们可以在struct中声明自己想要的变量,达到快速便捷的使用。
结构可以不用new 来实例化;
结构不能继承;
枚举(Enum)
枚举不能被继承,且枚举的成员始终是公开的,不能有访问修饰符。
using System;
public class EnumTest
{ 枚举 枚举名称 枚举元素
enum Day { Sun, Mon, Tue, Wed, Thu, Fri, Sat };
static void Main()
{
int x = (int)Day.Sun;
int y = (int)Day.Fri;
Console.WriteLine("Sun = {0}", x);
Console.WriteLine("Fri = {0}", y);
}
}
结果
Sun = 0
Fri = 5
我们分析结果,可以看出来,返回的是枚举的下标。
类
类在创建时可以省略访问修饰符,类的默认访问标识符是 internal(里面的),成员的默认访问标识符是 private(私有的)。
类的构造函数
using System;
namespace LineApplication
{
class Line
{
private double length; // 线条的长度
public Line()
{
Console.WriteLine("对象已创建");
}
public void setLength( double len )
{
length = len;
}
public double getLength()
{
return length;
}
static void Main(string[] args)
{
Line line = new Line();
// 设置线条长度
line.setLength(6.0);
Console.WriteLine("线条的长度: {0}", line.getLength());
Console.ReadKey();
}
}
}
结果:
对象已创建
线条的长度: 6
在执行改函数时,会将public Line()执行一次。也就是使用时会运行,当然,也可以有结束前运行的。
using System;
namespace LineApplication
{
class Line
{
private double length; // 线条的长度
public Line() // 构造函数
{
Console.WriteLine("对象已创建");
}
~Line() //析构函数
{
Console.WriteLine("对象已删除");
}
public void setLength( double len )
{
length = len;
}
public double getLength()
{
return length;
}
static void Main(string[] args)
{
Line line = new Line();
// 设置线条长度
line.setLength(6.0);
Console.WriteLine("线条的长度: {0}", line.getLength());
}
}
}
对象已创建
线条的长度: 6
对象已删除
静态成员
using System;
namespace StaticVarApplication
{
class StaticVar
{
public static int num;
public void count()
{
num++;
}
public int getNum()
{
return num;
}
}
class StaticTester
{
static void Main(string[] args)
{
StaticVar s1 = new StaticVar();
StaticVar s2 = new StaticVar();
s1.count();
s1.count();
s1.count();
s2.count();
s2.count();
s2.count();
Console.WriteLine("s1 的变量 num: {0}", s1.getNum());
Console.WriteLine("s2 的变量 num: {0}", s2.getNum());
Console.ReadKey();
}
}
}
结果:
s1 的变量 num: 6
s2 的变量 num: 6
我们通过上面的例子可以看到,创建了两个类,每个类执行了3次自加指令,但看结果可以看出来,他们都执行到了一个变量上面。也就是说,不管创建多少个新类,始终都是对同一个类成员进行操作。
也可以把一个成员函数修饰成静态的,这样就只能对静态变量进行操作。
using System;
namespace StaticVarApplication
{
class StaticVar
{
public static int num;
public void count()
{
num++;
}
public static int getNum()
{
return num;
}
}
class StaticTester
{
static void Main(string[] args)
{
StaticVar s = new StaticVar();
s.count();
s.count();
s.count();
Console.WriteLine("变量 num: {0}", StaticVar.getNum());
Console.ReadKey();
}
}
}
结果
变量 num: 3
继承
在程序中使用继承可以大幅减去我们创建一个新功能的时间,提高代码重用率,被继承的类称之为基类,新类称之为派生类。
<访问修饰符> class <基类>
{
...
}
class <派生类> : <基类>
{
...
}
一个类可以继承自多个父类。
多态性
什么是多态:同一个操作,作用于不同的对象时,会有不同的结果,即同一个方法根据需要,作用于不同的对象时,会有不同的实现。
C#的多态包括:接口多态,继承多态。
其中继承多态又包括通过虚拟方法实现的多态和通过抽象方法实现的多态性
例如:基类动物都有吃的方法,但是不同的动物吃的东西就会不一样,例如狼吃肉,羊吃草,这样“吃”的这个方法就要在派生类里面重新实现以下,运行时,通过指向基类的指针,来调用实现派生类中的方法。C#多态性
接口
待深入理解
方法的重载
在同一个类中,可以有相同的方法,但方法的传入参数类型不能一致,内部结构可以一致。
这种我们称之为方法的重载,比如Console.WriteLine可以接受str数据,也可以接受数字。
实例化的相同两个类可以进行相加,将两个类的当前值进行相加。
命名空间namespace
是为了在不同的命名空间中可以有相同的方法、函数、类。
比如在同一台电脑上可以有多个文件夹,每个文件夹中的文件名称可以重复,互不影响。
再比如,在生活中,小明有本红楼梦,小红也有一本红楼梦,同样是红楼梦,但不属于同一个人。
这样在一个庞大的代码系统中,可以更灵活的使用。
命名空间也可以嵌套命名空间,使用 . 符号来连接不同空间中的实例。
using 引用其它命名空间的代码,也称之为库。
预处理器指令
预处理器指令指导编译器在实际编译开始之前对信息进行预处理。
所有的预处理器指令都是以 # 开始。且在一行上,只有空白字符可以出现在预处理器指令之前。预处理器指令不是语句,所以它们不以分号(;)结束。
C# 编译器没有一个单独的预处理器,但是,指令被处理时就像是有一个单独的预处理器一样。在 C# 中,预处理器指令用于在条件编译中起作用。与 C 和 C++ 不同的是,它们不是用来创建宏。一个预处理器指令必须是该行上的唯一指令。
#define PI
using System;
namespace PreprocessorDAppl
{
class Program
{
static void Main(string[] args)
{
#if (PI)
Console.WriteLine("PI is defined");
#else
Console.WriteLine("PI is not defined");
#endif
Console.ReadKey();
}
}
}
结果
PI is defined
通过上方代码可以看出,我们用#define 定义了一个PI关键字,当#if(PI)成立时则会执行if下的代码,否则执行else,结束时执行endif。
进阶使用
#define DEBUG
#define VC_V10
using System;
public class TestClass
{
public static void Main()
{
#if (DEBUG && !VC_V10)
Console.WriteLine("DEBUG is defined");
#elif (!DEBUG && VC_V10)
Console.WriteLine("VC_V10 is defined");
#elif (DEBUG && VC_V10)
Console.WriteLine("DEBUG and VC_V10 are defined");
#else
Console.WriteLine("DEBUG and VC_V10 are not defined");
#endif
Console.ReadKey();
}
}
结果
DEBUG and VC_V10 are defined
预处理器的作用(用途)
当我们编写一个强大的系统时,可能会根据不同的用户,来展现不同的效果,那多种效果叠加在同一个程序中难免会有点拉跨,那我们可以在编译(使用)之前来告诉编译器,这一段是我目前不需要的,无需处理。进而提升性能。
因为它是在程序没有运行前就给出了答案,所以和普通的IF还是不同的。
正则表达式
正则表达式是用于在不同且复杂的文本中找出符合我们需要的信息,通过设置匹配规则,返回正确结果。
举例:
1.在工作群中,员工每天在群里汇报当天的出勤工时、项目号、工作内容,我们每天需要把这些信息整理汇总、存档。人为的去整理也可以,但效率不高,我们就可以利用正则表达式来根据规则提取出对应信息。
2.在用户创建一个密码时,我们可以用正则表达式来检查输入了多少个字母、数字、符号,从而引导用户设置一个安全的密码。
正则表达式笔记:正则表达式-新手笔记
看了教程,对它有了基础的了解,正则表达式的应用范围比较广,但归根结底功能都是一样的,只要掌握概念,需要哪种时,熟悉一下关键字,即可上手。
异常处理
在我们调试程序时,程序遇到错误,会报错并停止,但当我们把程序发布时,不能让他碰到错误就退出。如果用户操作问题,导致程序崩溃,无法使用,客户肯定不允许的。
我们可以利用对应方法来捕捉这些异常,给用户一个正确的反馈,引导用户做出正确的选择,防止程序崩溃。
举例
我们需要用户输入身高、体重等数字,但用户输入了汉字,汉字无法转int,程序报错停止,我们就可以利用try关键字捕捉错误,并反馈给客户原因。
在进行除法运算时如果用户输入了0,也可以捕捉该异常。
代码规范举例
try
{
// 引起异常的语句
}
catch( ExceptionName e1 )
{
// 错误处理代码
}
catch( ExceptionName e2 )
{
// 错误处理代码
}
catch( ExceptionName eN ) //该语句可以出现无数次,用于判断什么样的异常,并执行里面的代码。
{
// 错误处理代码
}
finally
{
// 要执行的语句 不管程序有没有报错,都会执行该段代码。
}
除0错误示范
using System;
namespace ErrorHandlingApplication
{
class DivNumbers
{
int result;
DivNumbers()
{
result = 0;
}
public void division(int num1, int num2)
{
try
{
result = num1 / num2;
}
catch (DivideByZeroException e)
{
Console.WriteLine("Exception caught: {0}", e);
}
finally
{
Console.WriteLine("Result: {0}", result);
}
}
static void Main(string[] args)
{
DivNumbers d = new DivNumbers();
d.division(25, 0);
Console.ReadKey();
}
}
}
结果:
Exception caught: System.DivideByZeroException: Attempted to divide by zero.
at ...
Result: 0
C#程序标识符:
在每行代码后面加英文分号表示该行代码结束。
Console.WriteLine("Hello World");
在使用方法时,传入的参数用英文括号包裹,方法内容写在大括号内部。
static void Main(string[] args)
{
/* 我的第一个 C# 程序*/
Console.WriteLine("Hello World");
Console.ReadKey();
}
该类语言对大小写比较敏感。
菜鸟教程C#教程-阅读理解与笔记。
记录自己的学习理解。