C#入门总结
本篇与C语言相同的部分不再阐述。
基础
1 快速入门
1.1 demo程序
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace helloworld
{
class program {
static void Main() {
Console.WriteLine("Hello, World! This is my first C# program!");
// Console.Read();
}
}
}
1.2 数据类型
与C一样的忽略。
byte
整型,范围0~255
decimal
浮点型,范围小于float和double,但精确度更高(28~29 digits)。
float精度为7digits,任何数字都表示为x.xxxxxxx,即小数点后最多7位;double范围比float大,并且精度为15~16digits。
对于浮点型,补充:
带小数点的数字变量默认为double型,其他浮点型,即使是初始化,也需要在赋值的数字后加上标识,如
double numberOfHours = 5120.5;
float hourlyRate = 60.5f;
decimal income = 25399.65m;
1.3 数组
数组初始化的多种方式
int[] userAge = {21, 22, 23, 24, 25};
int[] userAge = new int[5];
userAge = new [] {21, 22, 23, 24, 25};
数组便捷操作
数组长度userAge.Length
数组复制Array.Copy(source, dest, 3);,最后一位参数是拷贝长度。
数组排序Array.Sort(numbers);
数组元素查询Array.IndexOf(numbers, 21);,找到了返回下标,没找到返回-1。
1.4 字符串
C#支持string类型。
字符串可以直接拼接
string myName = “Hello World, ” + “my name is Jamie”;
//等价于
string myName = “Hello World, my name is Jamie”;
获取子串
string message = “Hello World”;
// We can then use message to call the Substring() method as shown below.
string newMessage = message.Substring(2, 5); //第一个参数是起始下标,第二个参数是长度
/* newMessage is thus equal to “llo W” */
判断字符串相等
string firstString = “This is Jamie”;
string secondString = “Hello”;
firstString.Equals(“This is Jamie”);
/* 相等返回true,不相等返回false */
字符串拆分
string [] separator = {“, ”, “; ”};
string names = “Peter, John; Andy, , David”;
string [] substrings = names.Split(separator, StringSplitOptions.None);
/* 结果为 {“Peter”, “John”, “Andy”, “” , “David”} */
/* 并且 */
string [] substrings = names.Split(separator, StringSplitOptions.RemoveEmptyEntries);
/* 结果为 {“Peter”, “John”, “Andy”, “David”} */
声明字段可为空
在类型后加一个?,如:
private string? name;
1.5 List
List类似于数组,但具有灵活可变性。
list初始化
List<int> userAgeList = new List<int>();
List<int> userAgeList = new List<int> {11, 21, 31, 41};
添加list元素
userAgeList.Add(51);
userAgeList.Add(61);
统计list元素数量userAgeList.Count
插入元素userAgeList.Insert(2, 51);
匹配删除元素userAgeList.Remove(51);
指定下标删除元素userAgeList.RemoveAt(3);
查询元素存在userAgeList.Contains(51);
清空listuserAgeList.Clear();
1.6 输入输出
输出
Console.WriteLine(“Hello ”);
Console.WriteLine(“How are you?”);
或
Console.Write(“Hello ”);
Console.Write(“How are you?”);
区别在于WriteLine()会自动换行,而Write()不会
可以使用
using static System.Console;,从而直接调用WriteLine(“Hello World”);
输出也支持+拼接,如
Console.WriteLine(“You scored ” + results + “ marks for your test.”);
支持占位符,如
Console.WriteLine(“{0}! You scored {1} marks for your test.”, “Good morning”, results);
//Good morning! You scored 79 marks for your test.
注意,中括号里的标号对应参数序号,如果位置调换,对应输出内容也会变
支持格式占位符,如
Console.WriteLine(“The number is {0:F3}.”, 123.45678);
//结果为The number is 123.457.
Console.WriteLine(“Deposit = {0:C}. Account balance = {1:C}.”, 2125, 12345.678);
//Deposit = $2,125.00. Account balance = $12,345.68
输入
int userInput = Console.Read(); //只读取单个字符,并且返回int型,字符需要用char类型转换得到
string userInput = Console.ReadLine(); //读取一行字符
int newUserInput = Convert.ToInt32(userInput); //读取的字符串转为数字
1.7 条件语句
忽略if, switch, for, while, do...while
foreach循环
主要用于数组或list,如
char[] message = { ‘H’, ‘e’, ‘l’, ‘l’, ‘o’ };
foreach (char i in message) {
Console.Write(i);
}
异常处理
格式
try {
//do something
} catch (type of error) {
//do something else when an error occurs
} finally {
//do this regardless of whether the try or catch condition is met.
}
catch可以有多个,finally为可选。
1.8 函数
准确来说,C#只有方法(Method),没有函数(Function)。
数组或list作为参数传入:
public void PrintFirstElement(int[] a) {
Console.WriteLine("The first element is {0}.\n", a[0]);
}
public void PrintFirstListElement(List<int> a) {
Console.WriteLine("The first list element is {0}.\n", a[0]);
}
调用:
MyClass a = new MyClass();
int[] myArray = { 1, 2, 3, 4, 5 };
a.PrintFirstElement(myArray);
//Passing list as an argument
List<int> myList = new List<int> { 1, 2, 3 };
a.PrintFirstListElement(myList);
函数如何返回数组或list?
设定函数返回类型,return对应类型变量即可,如
public int[] ReturnUserInput() {
int[] a = new int[3];
for (int i = 0; i < a.Length; i++) {
Console.Write("Enter an integer: ");
a[i] = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("Integer added to array.\n");
}
return a;
}
public List<int> ReturnUserInputList() {
List<int> a = new List<int>();
int input;
for (int i = 0; i < 3; i++) {
Console.Write("Enter an integer: ");
input = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("Integer added to list.\n");
a.Add(input);
}
return a;
}
1.9 待定参数
使用params关键字可以让函数参数数量具有可变性,例如
public void PrintNames(params string[] names) {
for (int i = 0; i < names.Length; i++)
{
Console.Write(names[i] + " ");
}
Console.WriteLine();
}
调用时可以输入不定量的参数
PrintNames(“Peter”);
PrintNames(“Yvonne”, “Jamie”);
PrintNames(“Abigail”, “Betty”, “Carol”, “David”);
1.10 修饰符权限
| 修饰符 | 级别 | 适用成员 | 解释 |
|---|---|---|---|
| public | 公开 | 类及类成员的修饰符 | 对访问成员没有级别限制 |
| private | 私有 | 类成员的修饰符 | 只能在类的内部访问 |
| protected | 受保护的 | 类成员的修饰符 | 在类的内部或者在派生类中访问,不管该类和派生类是不是在同一程序集中 |
| internal | 内部的 | 类和类成员的修饰符 | 只能在同一程序集(Assembly)中访问 |
1.11 枚举
C#的枚举基本与C一致。
示例:
namespace EnumDemo
{
class Program
{
static void Main(string[] args)
{
DaysOfWeek myDays = DaysOfWeek.Mon;
Console.WriteLine(myDays);
Console.WriteLine((int)myDays); //这样可以得到数字1
Console.WriteLine((DaysOfWeek)1); //这样可以得到"Mon"
Console.Read();
}
}
//枚举值默认从0开始
enum DaysOfWeek
{
Sun, Mon, Tues, Wed, Thurs, Fri, Sat
}
}
枚举值默认类型是int,但可以用:指定整型类型,如指定类型为byte:
enum DaysOfWeekThree : byte
{
Sun, Mon, Tues, Wed, Thurs, Fri, Sat
}
只能指定整型,除了char以外的整型类型都可以指定。
1.12 结构体
C#中的结构体,相当于以C的结构体为基础,拓展出了类似class的特性。
2 面向对象
2.1 基本元素
Class
class Staff {
//Contents of the class
//including fields, properties and methods
}
一个class中通常包含Fields, Properties, Method
Fields
字段,即成员变量。
private string nameOfStaff;
private const int hourlyRate = 30;
private int hWorked;
Properties
用于set或get私有变量,其中,set与get是C#特有关键词
public int HoursWorked {
get {
return hWorked;
}
set {
if (value > 0)
hWorked = value;
else
hWorked = 0;
}
}
在set中的value自动识别为实例赋值的右值
Method
方法,类比函数。
public void PrintMessage() {
Console.WriteLine(“Calculating Pay…”);
}
2.2 Overloading
重载,即允许存在相同名称但参数不同的函数,如
public int CalculatePay()
{
PrintMessage();
int staffPay;
staffPay = hWorked * hourlyRate ;
if (hWorked > 0)
return staffPay;
else
return 0;
}
public int CalculatePay(int bonus, int allowance)
{
PrintMessage();
if (hWorked > 0)
return hWorked * hourlyRate + bonus + allowance;
else
return 0;
}
特别地,C#默认会提供一个ToString()函数,返回class基本信息,而我们也可以将其重载
public override string ToString()
{
return "Name of Staff = " + nameOfStaff + ", hourlyRate = " +
hourlyRate + ", hWorked = " + hWorked;
}
2.3 Constructors
每个Class都需要至少有一个构造函数(至少一个是因为还可以重载),如
Class Staff
{
public Staff(string name) {
nameOfStaff = name;
Console.WriteLine("\n" + nameOfStaff);
Console.WriteLine("--------------------------");
}
public Staff(string firstName, string lastName) {
nameOfStaff = firstName + " " + lastName;
Console.WriteLine("\n" + nameOfStaff);
Console.WriteLine("--------------------------");
}
}
主要是用于实例化class变量时初始化,如在Main()函数中
Staff staff1 = new Staff("Peter");
2.4 Static
使用static关键字定义的成员函数,不需要实例化一个对象就可以使用,最典型的例子就是输出函数Console.WriteLine()。
例如
class MyClass
{
//Non static members
public string message = "Hello World";
public string Name { get; set; }
public void DisplayName()
{
Console.WriteLine("Name = {0}", Name);
}
//Static members
public static string greetings = "Good morning";
public static int Age { get; set; }
public static void DisplayAge()
{
Console.WriteLine("Age = {0}", Age);
}
}
访问静态与非静态成员函数:
static void Main(string[] args)
{
MyClass classA = new MyClass();
Console.WriteLine(classA.message);
classA.Name = "Jamie";
classA.DisplayName(); //访问前必须要实例化
Console.WriteLine(MyClass.greetings);
MyClass.Age = 39;
MyClass.DisplayAge(); //访问前不需要实例化
Console.Read();
}
2.5 Inheritance
类可以基于其他类新建,这样新建的类称为子类,子类可以继承父类的public与protected成员。
新建类时使用:来指定从哪个类继承,如
class Member
{
protected int annualFee;
private string name;
private int memberID;
private int memberSince;
public Member()
{
Console.WriteLine("Parent Constructor with no parameter");
}
public Member(string pName, int pMemberID, int pMemberSince)
{
Console.WriteLine("Parent Constructor with 3 parameters");
name = pName;
memberID = pMemberID;
memberSince = pMemberSince;
}
}
//从Member继承
class NormalMember : Member
{
public NormalMember()
{
Console.WriteLine("Child constructor with no parameter");
}
}
//从Member继承
class VIPMember : Member
{
//使用“:base”可以将子类构建函数的实参以相同的量优先传给父类构建函数
public VIPMember(string name, int memberID, int memberSince) : base(name, memberID, memberSince)
{
Console.WriteLine("Child Constructor with 3 parameters");
}
}
实例化一个子类,会先调用其父类的构建函数,之后再调用该子类的构建函数。
:base可以直接设置父类构建函数的实参,或者用该子类的形参赋值。
public NormalMember(string remarks) : base (“Jamie”, 1, 2015)
{
Console.WriteLine("Remarks = {0}", remarks);
}
public NormalMember(string remarks, string name, int memberID, int
memberSince) : base (name, memberID, memberSince)
{
Console.WriteLine("Child Constructor with 4 parameters");
Console.WriteLine("Remarks = {0}", remarks);
}
2.6 Polymorphism
多态,即在子类中重载父类的同名同参函数。
简单来看,执行一个在子类中新定义,但在父类中没有定义的函数,会产生错误;即使在子类与父类中定义了相同名称参数的函数,实际执行的也是父类中的函数。
C#不允许子类直接声明一个父类里的函数并填写新内容。
虽然自己试了下其实是可以的,但编译器会建议不要这么做。
为实现多态,需要:
- 在父类中定义可能需要在子类中重载的函数,并加上
virtual关键字; - 在子类中给重载的函数加上
override关键字。
编译器对多态的处理是实时的,即运行代码时,若父类函数带有virtual关键字,则编译器会找寻子类下是否有该函数override重载。
例如
//在Member中
public virtual void CalculateAnnualFee()
{
annualFee = 0;
}
//In VIPMember child class
public override void CalculateAnnualFee()
{
annualFee = 1200;
}
//In NormalMember child class
public override void CalculateAnnualFee()
{
annualFee = 100 + 12 * 30;
}
获取变量类型
由于多态的特性,我们有时会需要判断检查一下变量到底是哪一类型或类,使用GetType和typeof关键字可以实现这个要求。
例如:
if (clubMembers[0].GetType() == typeof(VIPMember)) {
Console.WriteLine(“Yes”);
} else {
Console.WriteLine(“No”);
}
GetType可以得到对象的类名,typeof则会返回某个具体类型,如int, float, 或类名
2.7 Abstract class
抽象类是一种特殊的类,专门用来作为基础类,供其他类继承。不能实例化,不能含有静态成员。同时,抽象类可以定义一种特殊的方法,名叫抽象方法;抽象方法不能写具体的内容,但继承的类中必须将其重载并填写执行内容。
定义抽象类与抽象方法:
abstract class MyAbstractClass
{
private string message = "Hello C#";
public void PrintMessage() {
Console.WriteLine(message);
}
public abstract void PrintMessageAbstract();
}
//继承了抽象类,对应类中的抽象方法必须重载并填写内容
class ClassA : MyAbstractClass
{
public override void PrintMessageAbstract() {
Console.WriteLine("C# is fun!");
}
}
2.8 Interface
接口是一种特殊的类,与抽象类很相似,不能被实例化,不能含有静态成员,并且必须被其他类继承。除此之外,接口类不能声明变量,只能声明无内容的方法。
接口类与抽象类更关键的一个区别是,一个子类只允许继承一个抽象类,但可以继承多个接口类。
示例:
interface IShape
{
int MyNumber {
get;
set;
}
void InterfaceMethod();
}
class ClassA : IShape
{
private int myNumber;
public int MyNumber {
get {
return myNumber;
}
set {
if (value < 0)
myNumber = 0;
else
myNumber = value;
}
}
public void InterfaceMethod() {
Console.WriteLine("The number is {0}.", MyNumber);
}
}
接口类的成员访问权限都是public,所以接口类中声明时不用特意写明public权限。
3 C#特性
3.1 LINQ
Language-Integrated Query是C#中提供的一种查询数据的特性。
附录
linux平台
下载mono
例如,centos系统,yum install mono-devel
编译C#程序:csc hello.cs或mcs hello.cs
运行程序:mono hello.exe

浙公网安备 33010602011771号