C# 基础语法 学习思维导图
一、类型系统
- C# 有两种类型:值类型和引用类型。
- 值类型的变量直接包含数据,而引用类型的变量则存储对数据(称为“对象”)的引用。
- 对于引用类型,两个变量可以引用同一个对象;对一个变量执行的运算可能会影响另一个变量引用的对象。
- 值类型,每个变量都有自己的数据副本;因此,对一个变量执行的运算不会影响另一个变量(ref 和 out 参数变量除外)
注意:在 C# 的统一类型系统中,所有类型(预定义类型、用户定义类型、引用类型和值类型)都是直接或间接从 Object 继承的。
1. 值类型
1.1简单类型
1.1.1 整数类型
整型类型的特征
在上表中,最左侧列中的每个 C# 类型关键字都是相应 .NET 类型的别名。 它们是可互换的。 例如,以下声明声明了相同类型的变量:
int a = 123;
System.Int32 b = 123;
举个栗子
using System;
namespace HelloWorld
{
class Program
{
static void Main(string[] args)
{
/**
* 计算机中的整数分为两类:
* (1)不带符号位的整数(unsigned integer,也称为无符号整数),
* 此类整数一定是正整数;
* (2)带符号位的整数(signed integer),
* 此类整数可以表示正整数,
* 又可以表示负整数
*/
sbyte b = -128;// 有符号 8 位整数 范围:-128 到 127
byte ub = 255; // 无符号的 8 位整数 范围:0 到 255
//错误赋值 byte errorb = 300;
// CS0031: Constant value '300' cannot be converted to a 'byte'
Console.WriteLine("sbyte="+b); //sbyte=-128
Console.WriteLine("byte="+ub); //byte=255
short ss = -32768; // 有符号 16 位整数 范围:-32,768 到 32,767
ushort us = 65535; // 有符号 16 位整数 范围:0 到 65,535
Console.WriteLine("short="+ss); //short=-32768
Console.WriteLine("ushort="+us); //ushort=65535
int i = -2147483648; // 带符号的 32 位整数 范围:-2,147,483,648 到 2,147,483,647
uint ui = 4294967295; // 无符号的 32 位整数 范围:0 到 4,294,967,295
Console.WriteLine("int="+i); //int=-2147483648
Console.WriteLine("uint="+ui); //uint=4294967295
long l = -9223372036854775; // 带符号的 64 位整数 范围:-9,223,372,036,854,775,808 到 9,223,372,036,854,775,807
ulong ul = 18446744073709551615; // 带符号的 64 位整数 范围:0 到 18,446,744,073,709,551,615
Console.WriteLine("long="+l); //long=-9223372036854775
Console.WriteLine("ulong="+ul); //ulong=18446744073709551615
}
}
}
1.1.2 字符类型
- 命名空间:
System
- 程序集:
System.Runtime.dll
public struct Char : IComparable, IComparable<char>, IConvertible, IEquatable<char>
- 继承 Object -> ValueType -> Char
- 实现 IComparable IComparable IConvertible IEquatable
举个栗子(一些字符方法)
using System;
public class CharStructureSample
{
public static void Main()
{
char chA = 'A';
char ch1 = '1';
string str = "test string";
Console.WriteLine(chA.CompareTo('B')); //----------- Output: "-1" (meaning 'A' is 1 less than 'B')
Console.WriteLine(chA.Equals('A')); //----------- Output: "True"
Console.WriteLine(Char.GetNumericValue(ch1)); //----------- Output: "1"
Console.WriteLine(Char.IsControl('\t')); //----------- Output: "True"
Console.WriteLine(Char.IsDigit(ch1)); //----------- Output: "True"
Console.WriteLine(Char.IsLetter(',')); //----------- Output: "False"
Console.WriteLine(Char.IsLower('u')); //----------- Output: "True"
Console.WriteLine(Char.IsNumber(ch1)); //----------- Output: "True"
Console.WriteLine(Char.IsPunctuation('.')); //----------- Output: "True"
Console.WriteLine(Char.IsSeparator(str, 4)); //----------- Output: "True"
Console.WriteLine(Char.IsSymbol('+')); //----------- Output: "True"
Console.WriteLine(Char.IsWhiteSpace(str, 4)); //----------- Output: "True"
Console.WriteLine(Char.Parse("S")); //----------- Output: "S"
Console.WriteLine(Char.ToLower('M')); //----------- Output: "m"
Console.WriteLine('x'.ToString()); //----------- Output: "x"
}
}
1.1.3 浮点数值类型
- 浮点数值类型表示实数。
- 所有浮点型数值类型均为值类型。
- 它们还是简单类型,可以使用文本进行初始化。
- 所有浮点数值类型都支持算术、比较和相等运算符。
浮点类型的特征
在上表中,最左侧列中的每个 C# 类型关键字都是相应 .NET 类型的别名。 它们是可互换的。 例如,以下声明声明了相同类型的变量:
double a = 12.3;
System.Double b = 12.3;
注意:decimal与 float 和 double 相比,decimal 类型具有更高的精度和更小的范围,因此它适合于财务和货币计算
举个栗子
/**
* 基础浮点类型赋值
* 将 _ 用作数字分隔符(从 C# 7.0 开始提供支持)。
* 可以将数字分隔符用于所有类型的数字文本。
*/
double d = 3D;
d = 4d;
d = 3.934_001;
float f = 3_000.5F;
f = 5.4f;
decimal myMoney = 3_000.5m;
myMoney = 400.75M;
/**
* 1.可在表达式中将整型类型与 float 和 double 类型混合使用功能。
* 在这种情况下,整型类型隐式转换为其中一种浮点类型且必要时,float 类型隐式转换为 double。
* 此表达式的计算方式如下:
* (1)如果表达式中有 double 类型,则表达式在关系比较和相等比较中求值得到 double 或 bool。
* (2)如果表达式中没有 double 类型,则表达式在关系比较和相等比较中求值得到 float 或 bool。
* 2.你还可在表达式中混合使用整型类型和 decimal 类型。
* 在这种情况下,整型类型隐式转换为 decimal 类型,并且表达式在关系比较和相等比较中求值得到 decimal 或 bool。
* 注意:不能在表达式中将 decimal 类型与 float 和 double 类型混合使用。
* 在这种情况下,
* 如果你想要执行算术运算、比较运算或相等运算,
* 则必须将操作数显式转换为 decimal 或反向转换,
* 如下例所示:
*/
double a = 1.0;
decimal b = 2.1m;
Console.WriteLine(a + (double)b);
Console.WriteLine((decimal)a + b);
1.2 枚举类型
枚举类型 是由基础整型数值类型的一组命名常量定义的值类型。
/**
*默认情况下,枚举成员的关联常数值为类型 int;
*它们从零开始,并按定义文本顺序递增 1。
*/
enum Season
{
Spring,
Summer,
Autumn,
Winter
}
//可以显式指定任何其他整数数值类型作为枚举类型的基础类型
enum ErrorCode : ushort
{
None = 0,
Unknown = 1,
ConnectionLost = 100,
OutlierReading = 200
}
//转换和使用
public class EnumConversionExample
{
public static void Main()
{
Season a = Season.Autumn;
Console.WriteLine($"Integral value of {a} is {(int)a}"); // output: Integral value of Autumn is 2
var b = (Season)1;
Console.WriteLine(b); // output: Summer
var c = (Season)4;
Console.WriteLine(c); // output: 4
}
}
1.3 结构类型
结构类型(“structure type”或“struct type”)是一种可封装数据和相关功能的值类型
public struct Coords
{
public Coords(double x, double y)
{
X = x;
Y = y;
}
public double X { get; }
public double Y { get; }
public override string ToString() => $"({X}, {Y})";
}
注意:
- 结构类型具有值语义 。
- 也就是说,结构类型的变量包含类型的实例。
- 默认情况下,在分配中,通过将参数传递给方法并返回方法结果来复制变量值。
- 对于结构类型变量,将复制该类型的实例。
1.4 可为空的值类型
C# 8.0 引入了可为空引用类型功能。
可为 null 值类型 T? 表示其基础值类型 T 的所有值及额外的 null 值。
例如,可以将以下三个值中的任意一个指定给 bool? 变量:true、false 或 null。
基础值类型 T 本身不能是可为空的值类型。
/**
* 声明和赋值
* 由于值类型可隐式转换为相应的可为空的值类型,
* 因此可以像向其基础值类型赋值一样,向可为空值类型的变量赋值。
* 还可分配 null 值。
*/
double? pi = 3.14;
char? letter = 'a';
int m2 = 10;
int? m = m2;
bool? flag = null;
// An array of a nullable value type:
int?[] arr = new int?[10];
/**
* 检查可为空值类型的实例
* 从 C# 7.0 开始,可以将 is 运算符与类型模式 结合使用,
* 既检查 null 的可为空值类型的实例,
* 又检索基础类型的值
*/
int? a = 42;
if (a is int valueOfA)
{
Console.WriteLine($"a is {valueOfA}");
}
else
{
Console.WriteLine("a does not have a value");
}
// Output:
// a is 42
/**
* 始终可以使用以下只读属性来检查和获取可为空值类型变量的值:
* Nullable<T>.HasValue 指示可为空值类型的实例是否有基础类型的值。
* 如果 HasValue 为 true,则 Nullable<T>.Value 获取基础类型的值。
* 如果 HasValue 为 false,则 Value 属性将引发 InvalidOperationException。
*/
int? b = 10;
if (b.HasValue)
{
Console.WriteLine($"b is {b.Value}");
}
else
{
Console.WriteLine("b does not have a value");
}
// Output:
// b is 10
/**
* 还可将可为空的值类型的变量与 null 进行比较,而不是使用 HasValue 属性
*/
int? c = 7;
if (c != null)
{
Console.WriteLine($"c is {c.Value}");
}
else
{
Console.WriteLine("c does not have a value");
}
// Output:
// c is 7
1.5 元祖类型
元组功能在 C# 7.0 及更高版本中可用,它提供了简洁的语法,用于将多个数据元素分组成一个轻型数据结构
/**
* 如何声明元组变量、对它进行初始化并访问其数据成员
*/
(double, int) t1 = (4.5, 3);
Console.WriteLine($"Tuple with elements {t1.Item1} and {t1.Item2}.");
// Output:
// Tuple with elements 4.5 and 3.
(double Sum, int Count) t2 = (4.5, 3);
Console.WriteLine($"Sum of {t2.Count} elements is {t2.Sum}.");
// Output:
// Sum of 3 elements is 4.5.
/**
* 如前面的示例所示,
* 若要定义元组类型,
* 需要指定其所有数据成员的类型,
* 或者,
* 可以指定字段名称。
* 虽然不能在元组类型中定义方法,
* 但可以使用 .NET 提供的方法
*/
(double, int) t = (4.5, 3);
Console.WriteLine(t.ToString());
Console.WriteLine($"Hash code of {t} is {t.GetHashCode()}.");
// Output:
// (4.5, 3)
// Hash code of (4.5, 3) is 718460086.
举个栗子
var xs = new[] { 4, 7, 9 };
var limits = FindMinMax(xs);
Console.WriteLine($"Limits of [{string.Join(" ", xs)}] are {limits.min} and {limits.max}");
// Output:
// Limits of [4 7 9] are 4 and 9
var ys = new[] { -9, 0, 67, 100 };
var (minimum, maximum) = FindMinMax(ys);
Console.WriteLine($"Limits of [{string.Join(" ", ys)}] are {minimum} and {maximum}");
// Output:
// Limits of [-9 0 67 100] are -9 and 100
(int min, int max) FindMinMax(int[] input)
{
if (input is null || input.Length == 0)
{
throw new ArgumentException("Cannot find minimum and maximum of a null or empty array.");
}
var min = int.MaxValue;
var max = int.MinValue;
foreach (var i in input)
{
if (i < min)
{
min = i;
}
if (i > max)
{
max = i;
}
}
return (min, max);
}
2. 值类型
2.1 类类型(class)
class TestClass
{
// Methods, properties, fields, events, delegates
// and nested classes go here.
}
在 C# 中仅允许单一继承。 也就是说,一个类仅能从一个基类继承实现。 但是,一个类可实现多个接口。
举个例子
/**
*下面的示例说明如何声明类字段、构造函数和方法。
*该示例还说明如何实例化对象及如何打印实例数据。
*本例声明了两个类。
*第一个类 Child 包含两个私*有字段(name 和 age)、两个公共构造函数和一个公共方法。
*第二个类 StringTest 用于包含 Main。
*/
class Child
{
private int age;
private string name;
// Default constructor:
public Child()
{
name = "N/A";
}
// Constructor:
public Child(string name, int age)
{
this.name = name;
this.age = age;
}
// Printing method:
public void PrintChild()
{
Console.WriteLine("{0}, {1} years old.", name, age);
}
}
class StringTest
{
static void Main()
{
// Create objects by using the new operator:
Child child1 = new Child("Craig", 11);
Child child2 = new Child("Sally", 10);
// Create an object using the default constructor:
Child child3 = new Child();
// Display results:
Console.Write("Child #1: ");
child1.PrintChild();
Console.Write("Child #2: ");
child2.PrintChild();
Console.Write("Child #3: ");
child3.PrintChild();
}
}
/* Output:
Child #1: Craig, 11 years old.
Child #2: Sally, 10 years old.
Child #3: N/A, 0 years old.
*/
2.2 接口
- 接口定义协定。
- 实现该协定的任何 class 或 struct 必须提供接口中定义的成员的实现。
注意:从 C# 8.0 开始,接口可为成员定义默认实现。 它还可以定义 static 成员,以便提供常见功能的单个实现
interface ISampleInterface
{
void SampleMethod();
}
class ImplementationClass : ISampleInterface
{
// Explicit interface member implementation:
void ISampleInterface.SampleMethod()
{
// Method implementation.
}
static void Main()
{
// Declare an interface instance.
ISampleInterface obj = new ImplementationClass();
// Call the member.
obj.SampleMethod();
}
}
举个栗子
interface IPoint
{
// Property signatures:
int X
{
get;
set;
}
int Y
{
get;
set;
}
double Distance
{
get;
}
}
class Point : IPoint
{
// Constructor:
public Point(int x, int y)
{
X = x;
Y = y;
}
// Property implementation:
public int X { get; set; }
public int Y { get; set; }
// Property implementation
public double Distance =>
Math.Sqrt(X * X + Y * Y);
}
class MainClass
{
static void PrintPoint(IPoint p)
{
Console.WriteLine("x={0}, y={1}", p.X, p.Y);
}
static void Main()
{
IPoint p = new Point(2, 3);
Console.Write("My Point: ");
PrintPoint(p);
}
}
// Output: My Point: x=2, y=3
2.3 数组类型
- 可以将同一类型的多个变量存储在一个数组数据结构中。
- 通过指定数组的元素类型来声明数组。
- 如果希望数组存储任意类型的元素,可将其类型指定为 object。
type[] arrayName;
举个栗子
class TestArraysClass
{
static void Main()
{
// Declare a single-dimensional array of 5 integers.
int[] array1 = new int[5];
// Declare and set array element values.
int[] array2 = new int[] { 1, 3, 5, 7, 9 };
// Alternative syntax.
int[] array3 = { 1, 2, 3, 4, 5, 6 };
// Declare a two dimensional array.
int[,] multiDimensionalArray1 = new int[2, 3];
// Declare and set array element values.
int[,] multiDimensionalArray2 = { { 1, 2, 3 }, { 4, 5, 6 } };
// Declare a jagged array.
int[][] jaggedArray = new int[6][];
// Set the values of the first array in the jagged array structure.
jaggedArray[0] = new int[4] { 1, 2, 3, 4 };
}
}
特点
- 数组可以是一维、多维或交错的。
- 创建数组实例时,将建立纬度数量和每个纬度的长度。 这些值在实例的生存期内无法更改。
- 数值数组元素的默认值设置为零,而引用元素设置为 null。
- 交错数组是数组的数组,因此其元素为引用类型且被初始化为 null。
- 数组从零开始编制索引:包含 n 元素的数组从 0 索引到 n-1。
- 数组元素可以是任何类型,其中包括数组类型。
- 数组类型是从抽象的基类型 Array 派生的引用类型。 由于此类型实现 IEnumerable 和 IEnumerable,因此可以在 C# 中的所有数组上使用 foreach 迭代。
2.4 委托(这个内容比较多)
- 类型的声明与方法签名相似。
- 它有一个返回值和任意数目任意类型的参数
public delegate void MessageDelegate(string message);
public delegate int AnotherDelegate(MyType m, long num);
- 在 .NET 中,System.Action 和 System.Func 类型为许多常见委托提供泛型定义。
- 可能不需要定义新的自定义委托类型。
- 相反,可以创建提供的泛型类型的实例化。
二、 类型和成员
三、程序构建基块