C# 是一个现代的、通用的、面向对象的编程语言,它是由微软(Microsoft)开发的,由
Ecma
和ISO
核准认可的。
C# 是专为公共语言基础结构(CLI)设计的。CLI
由可执行代码和运行时环境组成,允许在不同的计算机平台和体系结构上使用各种高级语言。
C# 成为一种广泛应用的专业语言的原因有以下几点:
C# 强大的编程功能
虽然 C# 的构想十分接近于传统高级语言 C
和 C++
,是一门面向对象的编程语言,但是它与 Java
非常相似,有许多强大的编程功能
下面列出 C# 一些重要的功能:
C# 是 .Net
框架的一部分,且用于编写 .Net
应用程序。
.Net 框架(.Net Framework)
.Net
框架是一个创新的平台,可以编写出下面类型的应用程序:
.Net
框架应用程序是多平台的应用程序。框架的设计方式使它适用于下列各种语言:
C#、C++、Visual Basic、Jscript、COBOL 等等。
所有这些语言可以访问框架,彼此之间也可以互相交互。
.Net
框架由一个巨大的代码库组成,用于 C# 等客户端语言。下面列出一些 .Net 框架的组件:
C# 编程的开发工具
C# 的集成开发环境(Integrated Development Environment - IDE)
微软(Microsoft)提供了下列用于 C# 编程的开发工具:
在 Linux 或 Mac OS 上编写 C# 程序
虽然 .NET 框架是运行在 Windows 操作系统上,但是也有一些运行于其它操作系统上的版本可供选择。Mono
是 .NET 框架的一个开源版本,它包含了一个 C# 编译器,且可运行于多种操作系统上,比如各种版本的 Linux
和 Mac OS
。
Mono
的目的不仅仅是跨平台地运行微软 .NET 应用程序,而且也为 Linux
开发者提供了更好的开发工具。Mono
可运行在多种操作系统上,包括 Android、BSD、iOS、Linux、OS X、Windows、Solaris 和 UNIX。
执行 C# 代码的过程包括下列步骤:
1.选择编译器
2.将代码编译为 MSIL
3.将MSIL
编译为本机代码
4.运行代码
5.垃圾回收
注:MSIL
包括用于加载,存储和初始化对象以及对对象调用方法的指令,还包括用于算术和逻辑运算,控制流,直接内存访问,异常处理和其他操作的指令。
在面向对象的编程方法中:
面向对象的程序设计思想是现代软件开发的基础
面向对象的程序由各种各样的类,对象和方法组成
一般而言,对象具有一下特性:
using 关键字:用于在程序中包含命名空间。一个程序可以包含多个 using 语句。在任何 C# 程序中的第一条语句都是:
using System;
class 关键字:用于声明一个类。
注释:用于解释代码,编译器会忽略注释的条目。在 C# 程序中,多行注释以 /* 开始,并以字符 */ 终止;单行注释是用 ‘//’ 符号表示。
C# 中 // 注释和 /// 注的区别::C# 引入了新的 XML 注释,即我们在某个函数前新起一行,输入 ///,VS.Net 会自动增加 XML 格式的注释
// 不会被编译,而 /// 会被编译
所以使用 /// 会减慢编译速度(但不会影响执行速度)
但使用 /// 会在其它的人调用你的代码时提供智能感知(通常在Form。Designer.cs 窗口会自动生成 /// 注释的程序)
成员变量:变量是类的属性或数据成员,用于存储数据。
成员函数:函数是一系列执行指定任务的语句。类的成员函数是在类内声明的。
C# 类的实例化:通过已有的类(class)创建出该类的一个对象(object),这一过程就叫做类的实例化。
标识符:标识符是用来识别类、变量、函数或任何其它用户定义的项目。在 C# 中,类的命名必须遵循如下基本规则:
C# 关键字:关键字是 C# 编译器预定义的保留字。这些关键字不能用作标识符,但是,如果想使用这些关键字作为标识符,可以在关键字前面加上@
字符作为前缀。在 C# 中,有些标识符在代码的上下文中有特殊的意义,如 get 和 set,这些被称为上下文关键字(contextual keywords)。
下表列出了 C# 中的保留关键字(Reserved Keywords)和上下文关键字(Contextual Keywords):
保留关键字列表
abstract | as | base | bool | break | byte | case |
---|---|---|---|---|---|---|
catch | char | checked | class | const | continue | decimal |
default | delegate | do | double | else | enum | event |
explicit | extern | false | finally | fixed | float | for |
foreach | goto | if | implicit | in | in (generic modifier) | int |
interface | internal | is | lock | long | namespace | new |
null | object | operator | out | out(generic modifier) | override | params |
private | protected | public | readonly | ref | return | sbyte |
sealed | short | sizeof | stackalloc | static | string | struct |
switch | this | throw | true | try | typeof | uint |
ulong | unchecked | unsafe | ushort | using | virtual | void |
volatile | while |
上下文关键字列表
add | alias | ascending | descending | dynamic | from | get |
---|---|---|---|---|---|---|
global | group | into | join | let | orderby | partial (type) |
partial (method) | remove | select | set |
字段:属性在类的声明中用变量表示,这样的变量称为字段(field)。
字段是在类声明的内部声明的,但是位于类的方法声明体之外。当类的每个对象维护自己的属性副本时,代表属性的字段又称为实例变量。
方法(Method):描述了类实际执行任务的机制,从形式上看,相当于C语言的函数
字段和方法都具有访问权限,主要为代码的安全考虑
通常有 3 种访问权限:private(私有的), public(公共的), protected(保护的)
使用权限:
命名空间:namespace中文多翻译为名字空间(或者命名空间)。
名字空间是用来组织和重用代码的编译单元,所谓namespace,是指标识符的各种可见范围。
System(名字空间).Console(类名).WriteLine(方法名)(“hello”)(要输出的函数参数);
在名字的开头使用 using 语句表示引用该名字空间,在代码书写中可以省略名字空间 。namespace
是 C# 的一个关键字,实际上,它只是起到标识作用,把需要的内容放到一起,细化管理,也可以定义自己的命名空间。
在新建C#项目时,会自动地把所有的东西放到一个新的名字空间里,这个名字空间默认的名字就是项目的名字
Main():一个项目可以就是你开发的一个软件,从扩展名来看,应用程序都会编译为一个 .exe 文件,既然是.exe文件,就表明它是可以被执行的。表现在程序中,这些应用程序都有一个主程序入口点,即Main()。
而类库,Windows控件等,则没有这个入口点,所以不能直接执行,而仅提供一些功能,给其他项目调用。这样的程序后缀名为 .dll
Visual Studio除了建立了一个控制台项目之外,该项目同时还属于一个解决方案
现在以下面这段代码为例找找这四种分别是什么:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace liti
{
class Program
{
static void Main(string[] args) //主函数
{
MyClass haha = new MyClass(); //创建新的类的实例
haha.SayHello(); //执行类里面的方法
}
}
class MyClass //类,MyClass是类名,可以自己命名,需要符合标识符的规定
{
private int x; //成员字段,可以存储一个数据
//因为使用权限是private,所以不可以在主函数里不可访问x
public void SayHello() //成员方法,相当于c语言里的函数
//因为使用权限是public,所以可以在主函数里可以访问SayHello
{
Console.WriteLine("hello world!");
}
}
}
在一行输入一个数据,求两个数的和
using System;
namespace liti
{
class Program
{
static void Main(string[] args)
{
//在一行输入一个数据
//Console.Read(); //读取一个字符
string s = Console.ReadLine(); //读取一行字符
int x = Convert.ToInt32(s); //将字符串转换为整数
s = Console.ReadLine();
int y = Convert.ToInt32(s); //必须手动转换
int z = x + y;
//Console.Write(z); //输出后不换行
Console.WriteLine(z); //输出后自动换行
//z会自动转换为字符输出
}
}
}
在一行输入多个数据,并求和
using System;
namespace liti
{
class Program
{
static void Main(string[] args)
{
//在一行输入多个数据
string s1 = Console.ReadLine(); //输入数据,中间用空格隔开
string[] ss1 = s1.Split(' '); //Split方法表示按括号内分隔符拆分字符串
//s1 是一个类,类中有很多方法,比如Split方法
double[] a = new double[ss1.Length]; //分配新的空间
double sum = 0;
for (int i = 0; i < ss1.Length; i++)
{
a[i] = Convert.ToDouble(ss1[i]); //将字符串转换为double型
sum = sum + a[i]; //求和
}
Console.WriteLine(sum);
//带格式输出
Console.WriteLine("和是{0}", sum); //大括号里的数必须从0开始
}
}
}
类型转换是把数据从一种类型转换为另一种类型。在 C# 中,类型转换有两种形式:
C# 提供了下列内置的类型转换方法:
序号 | 方法 | 描述 |
---|---|---|
1 | ToBoolean | 如果可能的话,把类型转换为布尔型。 |
2 | ToByte | 把类型转换为字节类型。 |
3 | ToChar | 如果可能的话,把类型转换为单个 Unicode 字符类型。 |
4 | ToDateTime | 把类型(整数或字符串类型)转换为日期-时间结构。 |
5 | ToDecimal | 把浮点型或整数类型转换为十进制类型。 |
6 | ToDouble | 把类型转换为双精度浮点型。 |
7 | ToInt16 | 把类型转换为 16 位整数类型。 |
8 | ToInt32 | 把类型转换为 32 位整数类型。 |
9 | ToInt64 | 把类型转换为 64 位整数类型。 |
10 | ToSbyte | 把类型转换为有符号字节类型。 |
11 | ToSingle | 把类型转换为小浮点数类型。 |
12 | ToString | 把类型转换为字符串类型。 |
13 | ToType | 把类型转换为指定类型。 |
14 | ToUInt16 | 把类型转换为 16 位无符号整数类型。 |
15 | ToUInt32 | 把类型转换为 32 位无符号整数类型。 |
16 | ToUInt64 | 把类型转换为 64 位无符号整数类型。 |
在 C# 中,变量分为以下几种类型:
值类型
值类型变量可以直接分配给其一个值。它们是从类 System.ValueType 中派生的。值类型直接包含数据。比如 int、char、float,它们分别存储数字、字母和浮点数。当声明一个 int 类型的变量时,系统将会分配内存来存储它的值。
如需得到一个类型或一个变量在特定平台上的准确大小,可以使用 sizeof
方法。表达式 sizeof(type) 产生以字节为单位存储对象或类型的存储尺寸。
引用类型
引用类型不包含存储在变量中的实际数据,但它们包含对变量的引用。
换句话说,它们指向的是一个内存位置。使用多重变量时,引用类型可以指向一个内存位置。如果内存位置的数据是由多重变量之中的一个改变的,其他变量会自动相应这种值的变化。例如,内置的引用类型有:object、dynamic 和 string。
对象类型
对象类型是 C# 通用类型系统(CTS)中所有数据类型基类。 Object 是 System.Object 类的别名。对象类型可以被分配任何其他类型(值类型、引用类型、预定义类型或用户自定义类型)的值。但是,在分配值之前,需要先进行类型转换。
当一个值类型转换为对象类型时,则被称为装箱;另一方面,当一个对象类型转换为值类型时,则被称为拆箱。
object obj;
obj = 100; // 这是装箱
动态类型
可以在动态数据类型变量中存储任何类型的值。这些变量的类型检查是在运行时进行的。
声明动态类型的语法:
dynamic
= value;
例如:
dynamic d = 20;
动态类型与对象类型相似,但是对象类型变量的类型检查是在编译时进行的,而动态类型变量的类型检查是在运行时进行的。
字符串类型
字符串类型允许给变量分配任何字符串值。字符串类型是 System.String 类的别名。它是从对象类型派生的。字符串类型的值可以通过两种形式进行分配:引号和 @ 引号。
指针类型
指针类型变量存储另一种类型的内存地址。C# 中的指针与 C 或 C++ 中的指针有相同的功能。
char* cptr; //声明指针
int* iptr;
根据代码了解下列知识:
int x; //声明变量
int y = 90; //声明常量
float a, b, c; //声明多个变量
float d = a + b + c; //表达式
bool k = a > b; //值为真或假
const double PI = 3.14159; //声明符号常量
decimal balabala = 0.0m;
//以上变量为值类型变量
int[] num = new int[100]; //引用型变量
NET中类型的两个基本类别是“值类型”和“引用类型”。
值类型:基元类型,枚举,结构
值类型包括:
引用类型:类,字符串,标准模块,接口,数组,委托
引用类型包括:
System.Object
, 它非常特殊,因为它既不是引用类型也不是值类型,而且不能实例化对于引用类型,两个变量可能引用同一个对象
对于值类型,每个变量都有它们自己的数据副本
C#值类型
定义:枚举类型是具有命名常量的独特的类型。每种枚举类型都具有一个基础类型,该基础类型必须是八种整数之一(如果没有声明是哪一种基础类型,默认是int类型)
枚举的声明:
访问修辞符 enum 枚举名:基础类型
{
枚举成员
}
枚举成员是该枚举类型的命名常数
任何两个枚举成员不能具有相同的名称
简单的枚举示例:
public enum time:uint
{
Morning = 1,
Afternoon = 2, //枚举成员之间用逗号隔开
Evening = 3 //最后一个枚举成员后面没有逗号
}
如果没有给枚举成员赋值,默认为0。以后的枚举成员值由前一个枚举成员的值加1得到
System.Enum 本身不是枚举类型。它是一个类类型,所有枚举类型都是从它派生的
定义:结构是使用 struct
关键字定义的,与类相似,都表示可以包含数据成员和函数成员的数据结构。
结构是一种值类型,并且不需要堆分配(不使用 new 运算符)
结构不能声明默认构造函数或析构函数
简单的结构示例:
struct Haha
{
public int x;
public int y;
public static string str = null; //静态变量可以初始化
public Haha(int x, int y) //带参数的构造函数
{
this.x = x;
this.y = y;
Console.WriteLine("x = {0}, y = {1}, str = {2}", x, y, str);
}
}
关于枚举和结构如何使用的例子:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace litii
{
class Program
{
struct Haha //结构
{
public int age;
public string name;
}
enum DayTime //枚举
{
Morning,
Afternoon,
Evening
}
static void Main(string[] args) //主函数
{
Haha s1;
s1.age = 18;
Haha[] s2 = new Haha[100];
DayTime d1;
d1 = DayTime.Morning;
}
}
}
C#引用类型
C#类型由用户定义的类别:类类型,结构类型,接口类型,枚举类型,委托类型
引用类型的值都被当做 “ 对象 ” 来处理
值类型的值则通过执行装箱和拆箱操作亦按对象处理
示例:
int i = 123;
object o = i; //装箱
int j = (int)o; //拆箱
由于这种统一性,使用 object
类型的通用库既可以用于引用类型,又可以用于值类型
关于后缀:
C#提供的字符类型数据按照国际上公认的标准,采用 Unicode
字符集。一个Unicode 字符的长度为 16 位( bit ),它可以用来表示世界上大部分语言种类。所有 Unicode 字符的集合构成字符类型。字符类型的类型标识符是 char, 因此也可称为 char 类型。
在表示一个字符常数时,单引号内的有效字符数量必须且只能是一个,并且不能是单引号或则反斜杠( \ ) 。
一个字符串是被双引号包含的一系列字符。
C#支持的字符串常数:
1.常规字符串常数
2.逐字字符串常数:@ 开头的字符串
例如:@ “ 计算机 ”
逐字字符串常数同常规字符串常数的区别在于,在逐字字符串常数的双引号中,每个字符都代表其最原始的意义,在逐字字符串常数中没有转义字符。
推断类型可以是内置类型,匿名类型,用户定义类型或,NET Framework 类库中定义的类型。
var i = 10; //隐式声明
int i = 10; //显示声明
//两句功能一样,前者更加方便简介一些
表达式
概念:表达式是由运算符将运算对象(如常数,变量和函数等)连接起来的具有合法语义的式子。
注:如果除数和被除数均为整数类型,则结果也是整数。(只取整数部分)
“ % ” 运算符两侧均应为整型数据,其运算结果为两个运算对象作除法运算的余数。
位运算符:
1.按位与( & ):两个整型数据中的二进制做 “ 与 ” 运算。
“ 与 ” 运算规则为:如果参加运算的两个二进制位均为 1 ,则结果为 1 ,否则结果为 0 。
2.按位或( | ):两个整形数据中的二进制位做 “ 或 ” 运算。
“ 或 ” 运算规则为:只要参加运算的两个二进制位中有一个为 1 ,则结果就是 1;只有在参加运算的两个 2 进制位均为 0 的情况下结果才是 0。
3.按位异或( ^ ):两个整型数据中的二进制位做 “ 异或 ” 运算。
“ 异或 ” 运算规则为:如果参加运算的两个二进制位不同则运算结果为 1,相同则结果为 0。
4.按位取反( ~ ):按位取反是单目运算符,只需一个运算对象,按位取反运算将作为运算对象的整型数据中的二进制位做 “ 求反 ” 运算。
“ 求反 ”运算规则:如果原来的二进制位为 1,则运算结果为 0,否则结果为 1,即运算结果和原来的数据相反。
5.左移位运算符( << ):左移位运算符用于将整型数据中的各个二进制位全部左移若干位,并在该数据的右端添加相同个数的 0。
6.右移位运算符( >> ):右移位运算符用于将整型数据中的各个二进制位全部右移若干位,并在该数据的左端添加相同个数的 0。
C#中的数学函数大多是 Math
类的静态方法,而 Math 类在名字空间 System 中。
例如:
double y = Math.Cos(0.5);
面向对象编程( Object Oriented Programming, OOP, 面向对象程序设计)是一种计算机编程架构。
面向对象编程中的概念主要包括:
类,对象,数据抽象,数据封装,继承,动态绑定,多态性,消息传递。
最基本的特征:封装,继承,多态
通过继承可以创建:派生类,基类
派生类可以从其基类中继承属性和方法
继承的目的:代码的重用
多态性是指不同类的对象对同一消息作出不同的响应
多态的作用:实现接口重用
类是对一些具有相同数据和操作的事物的描述
在C#中,数据称为字段,操作称为方法
类的其中两个成员:
类修饰符:限定声明类的一种符号
成员修饰符:
字段初始值:
每种类型的默认值都是0;bool型时是false;引用类型默认为null。
构造方法:没有返回值,名字和类名相同,可以传递参数,可以重载
例如:
public Person() //没有参数的构造方法
{
Name = "lili";
Age = 18;
Weight = 126;
}
类的属性:C#中属性体现了对象的封装性。
属性是类、结构体和接口的命名成员。类或结构体中的成员变量或方法称为域。属性是域的扩展,且可使用相同的语法来访问。它们使用访问器让私有域的值可被读写或操作。
属性不会确定存储位置。相反,它们具有可读写或计算它们值的访问器。
例如,有一个名为 Student 的类,带有 age、name 和 code 的私有域。我们不能在类的范围以外直接访问这些域,但是我们可以拥有访问这些私有域的属性。
访问器
属性的访问器包含有助于获取(读取或计算)或设置(写入)属性的可执行语句。访问器声明可包含一个 get
访问器、一个 set
访问器,或者同时包含二者。
private string id = "1919";
public string ID
{
get
{
return id;
}
set
{
id = value;
}
}
// public string ID { get; set; } 与上面代码效果一样
数据类型的存储方式,位置:
栈是一个内存数组,是一个LIFO(last-in first-out,后进先出)的数据结构。
栈存储几种类型的数据:
堆是一块内存区域,在堆里可以分配大块的内存用于存储某类型的数据
所有引用类型的数据都会分配到堆里面(使用 new 分配内存)
值类型只需要一段单独的内存,用于存储实际的数据
引用类型需要两端内存:
第一段存储实际的数据,位于堆中;
第二段是一个引用,指向数据在堆中存放位置。
看下面一道例题理解下列知识:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace litii
{
class Program
{
static void Main(string[] args)
{
Hero baizd = new Hero();
baizd.AddLife();
baizd.Life = 90; //自动调用属性中的set过程,90这个值会传递给value
int k = baizd.Life; //自动调用属性中的get过程
//属性在等号左边调用set过程,属性在等号右边调用get过程
}
}
class Hero //类
{
private string name; //字段
private int life = 50;
public int Life //属性
{
get
{
return life;
}
set //根据需要写不同的代码
{
if (value < 0)
life = 0;
else
{
if (value > 100)
life = 100;
else
life = value;
}
}
}
public string Name //属性
{
get
{
return name;
}
set
{
name = value;
}
}
public int Age { get; set; } //如果不需要做任何处理,可以这样写(可不写)
//效果和 Name 属性一样
public void AddLife() //方法
{
life++;
}
public Hero() //构造方法,在创建实例的时候自动被调用,且只被调用一次
{
life = 0; //如果一个类没有写构造方法,系统会自动添加一个构造方法
name = " "; //不需要写返回值
}
~Hero() //默认权限为private
{
//析构方法,销毁构造方法
}
}
}
例题:输入三个数判断这三个数是否可以构成三角形
using System;
namespace litii
{
class Program
{
static void Main(string[] args)
{
double a, b, c;
//string s = Console.ReadLine();
var s = Console.ReadLine();
var ss = s.Split(' ');
a = Convert.ToDouble(ss[0]);
b = Convert.ToDouble(ss[1]);
c = Convert.ToDouble(ss[2]);
if (a + b > c && b + c > a && a + c > b)
{
Console.WriteLine("YES");
}
else
{
Console.WriteLine("NO");
}
}
}
}
using System;
namespace litii
{
class Program
{
static void Main(string[] args)
{
int a;
var s = Console.ReadLine();
a = Convert.ToInt32(s);
int sum = 0;
int aNext = a;
//int n = 0;
//while (n < 7)
//{
// sum = sum + aNext;
// aNext = aNext * 10 + a;
// n++;
//}
//int n = 0;
//do
//{
// sum = sum + aNext;
// aNext = aNext * 10 + a;
// n++;
//} while (n < 7);
for (int i = 1; i <= 7; i++)
{
sum = sum + aNext;
aNext = aNext * 10 + a;
}
Console.WriteLine("Sum={0}", sum);
}
}
}
using System;
namespace litii
{
class Program
{
static void Main(string[] args)
{
var s = Console.ReadLine();
int garde = Convert.ToInt32(s);
int f;
switch (garde / 10)
{
case 10: //什么都没有可以不加break
case 9:
f = 5;
break;
case 8:
f = 4;
break;
case 7:
f = 3;
break;
default:
f = 1;
break;
}
Console.WriteLine("f={0}", f);
for (int i = 0; i < 3; i++)
{
if (f == 1)
{
continue;
}
else
{
Console.WriteLine("nice!");
}
}
}
}
}
一维数组
声明和创建一维数组
int[] arr = new int [5];
//数组类型[] 数组名 = new 数组类型[数组长度]
int[] arr1 = new int[5]{1,2,3,4,5}; //初始化
// int[] arr1 = new int[]{1,2,3,4,5}; //简略的写法
// int[] arr1 = {1,2,3,4,5}; //简略的写法
//初始值的个数要和数组长度一致
//数组的长度可以是变量
多维数组
//二维数组
int[,] arr = new int[2,3]; //声明
int[,] arr = new int[2,3]{{1, 2, 3},{4, 5, 6}}; //初始化
int[,] arr = new int[,]{{1, 2, 3},{4, 5, 6}}; //简略的写法
int[,] arr = new {{1, 2, 3},{4, 5, 6}}; //大括号里的大括号不可以省略
//数组类型[,] 数组名 = new 数组类型[m, n];
//m, n可以是变量或常量表达式
交错数组
//二维交错数组
int[][] jagarr = new int[3][]; //交错数组的声明,第二个[]中不用写数值
jagarr[0] = new int[5];
jagarr[1] = new int[4];
jagarr[2] = new int[2];
//初始化
jagarr[0] = new int[]{1, 2, 3, 4, 5};
jagarr[1] = new int[]{11, 22, 33, 44,};
jagarr[2] = new int[]{123, 456};
例题:随机填充一维数组,并在数组中顺序查找
产生 100 个 1~99 之间的随机整数,填充数组
输入一个 1~99 之间的数,如果该数字在数组中,则输出该数字在数组中的下标,
如果不在,输出-1,如果有多个,仅输出第一个匹配的下标
using System;
namespace lii
{
class Program
{
static void Main(string[] args)
{
int[] a = new int[100];
Random r = new Random();
for (int i = 0; i < a.Length; i++)
{
a[i] = r.Next(1, 100);
//括号里为产生随机数的上限和下限,下限可取,上限不可取
}
foreach(int k in a) //输出
{
Console.Write("{0} ", k);
}
int m = Convert.ToInt32(Console.ReadLine());
for (int i = 0; i < a.Length; i++)
{
if (m == a[i])
{
Console.WriteLine("m的位置{0}",i);
return;
}
}
Console.WriteLine("-1");
}
}
}
利用交错数组生成杨辉三角
using System;
namespace lii
{
class Program
{
static void Main(string[] args)
{
const int N = 10;
int[][] pas = new int[N][]; //定义交错数组
for(int i = 0; i < N; i++)
pas[i] = new int[i + 1]; //为交错数组分配空间
pas[0][0] = 1;
for(int i = 1; i < N; i++)
{
pas[i][0] = 1;
pas[i][i] = 1;
for(int j = 1; j < i; j++)
pas[i][j] = pas[i - 1][j - 1] + pas[i - 1][j];
}
for(int i = 0; i < N; i++)
{
for(int j = 0; j <= i; j++)
{
Console.Write("{0,-4}",pas[i][j]);
}
Console.WriteLine();
}
}
}
}
静态方法和静态变量
static
修饰符声明的成员称为静态成员static
声明的成员(域,字段)变量称为静态变量static
声明的方法称为静态方法方法的声明:
方法在类或结构中声明,声明时需要指定访问级别(即访问修饰符),返回值,方法名,方法参数以及方法体。
方法的使用:
有返回值,方法调用仅作为表达式的形式出现
using System;
namespace lii
{
class Program
{
static void Main(string[] args) //静态方法
{
sun s = new sun();
sun s1 = new sun();
//s.sm(); //error
sun.sm(); //"."之前是类名,不是实例名
Console.WriteLine(sun.count++); //参数必须是静态的
}
}
class sun
{
public static int count = 0;
public int a = 0;
public static void sm()
{
Console.WriteLine("haha");
}
public sun()
{
count++;
}
}
}
方法的参数传递:
using System;
namespace titi
{
class Program
{
static void Main(string[] args)
{
int a = 10;
int b = 99;
Swap(a, b);
Console.WriteLine("a={0},b={1}", a, b); //输出的 a = 10, b = 99
Swap2(ref a, ref b);
Console.WriteLine("a={0},b={1}",a, b); //输出 a = 99, b = 10
}
static void Swap(int a,int b) //值参数进行值传递
{
int t = a;
a = b;
b = t;
Console.WriteLine("a={0},b={1}", a, b); //输出的 a = 99, b = 10
}
static void Swap2(ref int a, ref int b) //值参数进行引用传递
{
int t = a;
a = b;
b = t;
Console.WriteLine("a={0},b={1}", a, b); //输出的 a = 99, b = 10
}
}
}
ref
修饰符标记的参数(声明和调用时都要标记)using System;
namespace titi
{
class Program
{
static void Main(string[] args)
{
int[] a = { 1, 2, 3 };
AddOne(a);
foreach (int k in a)
Console.WriteLine(k); // 输出为 1 2 3
AddOne2(ref a);
foreach (int k in a)
Console.WriteLine(k); // 输出为 12 13 14 15
}
static void AddOne(int[] a) //引用参数进行值传递
{
a = new int[4] { 11, 12, 13, 14 }; //如果不加该语句输出为 2 3 4
for (int i = 0; i < a.Length; i++)
{
a[i]++;
}
}
static void AddOne2(ref int[] a) //引用参数进行引用传递
{
a = new int[4] { 11, 12, 13, 14 }; //如果不加该语句输出为 3 4 5
for (int i = 0; i < a.Length; i++)
{
a[i]++;
}
}
}
}
out参数
输出(OUT参数)
使用一个方法,返回 2 个整数的和以及差
using System;
namespace titi
{
class Program
{
static void Main(string[] args)
{
int x1 = 7;
int x2 = 11;
int x3;
int x4;
AddM(x1, x2 ,out x3, out x4); //用out函数不用给变量赋初值
Console.WriteLine("{0},{1}", x3, x4);
}
static void AddM(int x1, int x2, out int x3, out int x4)
{
x3 = x1 + x2;
x4 = x1 - x2;
}
}
}
可选参数和命名参数
using System;
namespace titi
{
class Program
{
static void Main(string[] args)
{
int a = 7;
int b = 10;
char c = 'Y';
Sun(a, b, c);
Sun(a,b); //正确
Sun(a, 1, c);
Sun(a, c: c); //命名参数
}
static void Sun(int a, int b = 1, char c = 'R') // b,c为可选参数
{
a = a + 1;
Console.WriteLine("{0},{1},{2}", a, b, c);
}
}
}
运行结果
8,10,Y
8,10,R
8,1,Y
8,1,Y
变长参数表
使用变长参数,求若干个整数的平均值
using System;
namespace titi
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(Average(1));
Console.WriteLine(Average(1, 2, 3, 4));
}
static double Average(params int[] a) //变长参数表
{
int b = a.GetLength(0);
double s = 0;
foreach (int k in a)
s += k;
return s / b;
}
}
}
方法的重载
using System;
namespace titi
{
class Program
{
static void Main(string[] args)
{
double area = Area(3d, 4d, 5d);
double area1 = Area(3, 4, 5);
}
static double Area(double a,double b,double c)
{
Console.WriteLine("1");
double s = (a + b + c) / 2;
return Math.Sqrt(s * (s - a) * (s - b) * (s - c));
}
static double Area(double a,double h)
{
Console.WriteLine("2");
return (a * h) / 2;
}
static double Area(int a, int b,double theta)
{
Console.WriteLine("3");
return (a * b * Math.Sin(theta)) / 2;
}
}
}
readonly:如果类中变量的值在构造函数中进行初始化,初始化后就不能修改,但不同的对象调用构造函数时可以将该变量初始化为不同的值,这样变量可以使用readonly关键字进行修饰,只读变量
面向对象程序设计中最重要的一个概念就是继承(inheritance)。继承允许我们在另一个类中定义一个新的类,这使得它更容易创建和维护一个应用程序。这也提供了一个机会来重用代码的功能,加快实现时间。
创建一个类的时候,不是要写全新的数据成员和成员函数,程序员可以指定新的类继承一个已经存在的类的成员。已有的类称为基类(base class),新的类称为派生类(derived class)。
基类和派生类
派生类只能有一个直接基类,但一个基类可以有多个直接派生类。继承是可以传递的。定义要从其他类派生的类时,派生类会隐式获得基类的所有成员(除了其构造函数和终结器)。派生类因而可以重用基类中的代码,而无需重新实现。在派生类中,可以添加更多成员。通过这种方法,派生类可扩展基类的功能。
复数类
using System;
namespace titi
{
class Program
{
static void Main(string[] args)
{
Complex x1 = new Complex(2, 3);
Complex x2 = new Complex(5.6, 7.8);
Complex x3 = x1.ADD(x2);
x3.Show();
Complex x4 = Complex.Add(x1, x2);
x4.Show();
}
}
public class Complex
{
private double real;
private double image;
public Complex()
{
real = image = 0;
}
public Complex (double real,double image)
{
this.real = real;
this.image = image;
}
public void Set(double real,double image)
{
this.real = real;
this.image = image;
}
public double GetReal()
{
return real;
}
public double GetImage()
{
return image;
}
public Complex ADD(Complex x)
{
Complex temp = new Complex();
temp.real = this.real + x.real;
temp.image = this.image + x.image;
return temp;
}
public static Complex Add(Complex x1,Complex x2)
{
Complex temp = new Complex();
temp.real = x1.real + x2.real;
temp.image = x1.image + x2.image;
return temp;
}
public Complex Sub(Complex x)
{
Complex temp = new Complex();
temp.real = this.real - x.real;
temp.image = this.image - x.image;
return temp;
}
public void Show()
{
Console.Write("{0}+{1}i", real, image);
}
}
}