引用类型
继承基类,除了构造函数的其他所有成员。在 C# 中,类只能直接继承单一基类;类可以实现一个或多个接口。
abstract 抽象类,可以拥有抽象方法(只定义,未实现功能)。抽象类不能被实例化
值类型
字段是 class 或者 struct 中直接声明的任何类型的变量
class 或者 struct 可能包含实例字段、静态字段。实例字段独立于类对象,改变各自对象的实例字段,不会影响到其他对象中的实例字段。相比之下,静态字段属于类自己,改变类对象的静态字段,会立即影响到其他类对象中的此静态字段。
通常,只将字段用于具有 private protected 访问属性的变量。
字段在构造函数执行之前会被立即初始化。
public 可以被同一程序集中的任何代码,或者引用它的其他程序集访问
private 只可以被同一 class 或者 struct 的代码访问
protected 只能被同一 class 或者派生自该类的类的代码访问
internal 可以被同一程序集中的任何代码访问,不能被其他程序集中的代码访问
protected internal 可以被声明它的程序集中的任何代码访问,或者从另一程序集中的派生类中的代码访问
private protected 只可以在声明它的程序集中,被同一类或者派生自该类的代码访问
static field 可以在任何时间呼叫,甚至不通过类的实例,直接通过类呼叫。
readonly field 只能在初始化,或者构造函数中分派值。
static readonly field 类似于常量,不同的是 C# 编译器在编译阶段不能访问 static readonly field 只有在运行阶段可以访问。
常量在整个程式运行生命期不可改变值。只有 C# Build-In Type(除了 System.Object) 可以被声明为常量。
class Calendar1
{
public const int Months = 12;
}
class Calendar2
{
public const int Months = 12, Weeks = 52, Days = 365;
}
class Calendar3
{
public const int Months = 12;
public const int Weeks = 52;
public const int Days = 365;
public const double DaysPerWeek = (double) Days / (double) Weeks;
public const double DaysPerMonth = (double) Days / (double) Months;
}
int birthstones = Calendar.Months;
注意:若引用声明在其它代码中的常量(例如(DLLs)中),若该 DLL 声明了该常量的新值,该程式依旧持有该常量的旧值,直到重新编译该程式的版本。
属性(property)是一种成员,它提供灵活的机制来读取、写入、计算私有字段的值。
// Properties with backing fields
using System;
class TimePeriod
{
private double _seconds;
public double Hours
{
get { return _seconds / 3600; }
set {
if (value < 0 || value > 24)
throw new ArgumentOutOfRangeException(
$"{nameof(value)} must be between 0 and 24.");
_seconds = value * 3600;
}
}
}
class Program
{
static void Main()
{
TimePeriod t = new TimePeriod();
// The property assignment causes the 'set' accessor to be called.
t.Hours = 24;
// Retrieving the property causes the 'get' accessor to be called.
Console.WriteLine($"Time in hours: {t.Hours}");
}
}
// The example displays the following output:
// Time in hours: 24
// Expression body definitions
using System;
public class Person
{
private string _firstName;
private string _lastName;
public Person(string first, string last)
{
_firstName = first;
_lastName = last;
}
public string Name => $"{_firstName} {_lastName}";
}
public class Example
{
public static void Main()
{
var person = new Person("Isabelle", "Butts");
Console.WriteLine(person.Name);
}
}
// The example displays the following output:
// Isabelle Butts
// Auto-implemented properties
using System;
public class SaleItem
{
public string Name
{ get; set; }
public decimal Price
{ get; set; }
}
class Program
{
static void Main(string[] args)
{
var item = new SaleItem{ Name = "Shoes", Price = 19.95m };
Console.WriteLine($"{item.Name}: sells for {item.Price:C2}");
}
}
// The example displays output like the following:
// Shoes: sells for $19.95
方法(method)声明于 class 或者 struct 中,可以使用 public private 访问级别符修饰,可选修饰符为 abstract sealed
方法声明时,称为:parameter 方法调用时,称为:argument
默认情况下,若将值类型传入方法中,方法得到的是该值类型对象的复制版本,因此对此参数的更改,不会影响到方法调用中的原始副本。可以通过使用 ref 关键字,通过引用方式传入值类型。
若使用 async 修饰方法,就可以在方法中使用 await 操作符,挂起方法的执行。异步方法的返回值类型可以为:Task
返回值为 void 的异步方法,主要用于事件处理程式的声明。异步方法不能定义 ref 或者 out 的方法变量
public Point Move(int dx, int dy) => new Point(x + dx, y + dy);
public void Print() => Console.WriteLine(First + " " + Last);
// Works with operators, properties, and indexers too.
public static Complex operator +(Complex a, Complex b) => a.Add(b);
public string Name => First + " " + Last;
public Customer this[long id] => store.LookupCustomer(id);
当 class 或者 struct 被创建时,构造函数会被呼叫。若没有为 class 提供构造函数,C# 会默认创建一个无参的构造函数。
public class Person
{
private string last;
private string first;
public Person(string lastName, string firstName)
{
last = lastName;
first = firstName;
}
// Remaining implementation of Person class.
}
public class Location
{
private string locationName;
public Location(string name) => Name = name;
public string Name
{
get => locationName;
set => locationName = value;
}
}
class 或者 struct 可以拥有静态构造函数,其用来初始化此种类型中的静态成员。静态构造函数必须声明为无参数的。
public class Child : Person
{
private static int maximumAge;
public Child(string lastName, string firstName) : base(lastName, firstName)
{ }
static Child() => maximumAge = 18;
// Remaining implementation of Child class.
}
事件使 class 或者对象,在发生某些情况时可以通知其他 class 或者对象。
终接器(又称为 destructors 析构函数),用于在对象被垃圾回收器回收时,执行最终清理工作。
索引器允许 class 或者 struct 的实例像数组一样被索引。
using System;
class SampleCollection
{
// Declare an array to store the data elements.
private T[] arr = new T[100];
// Define the indexer to allow client code to use [] notation.
public T this[int i]
{
get { return arr[i]; }
set { arr[i] = value; }
}
}
class Program
{
static void Main()
{
var stringCollection = new SampleCollection();
stringCollection[0] = "Hello, World";
Console.WriteLine(stringCollection[0]);
}
}
// The example displays the following output:
// Hello, World.
// Expression Body Definitions
using System;
namespace ASP_NET_Roadmap.Classes_and_Structs
{
public class SampleCollection1
{
// Declare an array to store the data elements.
private T[] arr = new T[100];
int nextIndex = 0;
// Define the indexer to allow client code to use [] notation.
// C# 6.0 支持
public T this[int i] => arr[i];
public void Add(T value)
{
if (nextIndex > arr.Length)
{
throw new IndexOutOfRangeException($"The collection can hold only {arr.Length} elements.");
}
arr[nextIndex++] = value;
}
}
}
using System;
namespace ASP_NET_Roadmap.Classes_and_Structs
{
public class SampleCollection2
{
// Declare an array to store the data elements.
private T[] arr = new T[100];
// Define the indexer to allow client code to use [] notation.
// C# 7.0 支持
public T this[int i]
{
get => arr[i];
set => arr[i] = value;
}
}
}
声明在 class 或者 struct 中的类型,称为嵌套类型。嵌套类型的默认访问属性为:private
class Container
{
class Nested
{
Nested() { }
}
}
class Container
{
public class Nested
{
Nested() { }
}
}
public class Container
{
public class Nested
{
private Container parent;
public Nested()
{
}
public Nested(Container parent)
{
this.parent = parent;
}
}
}
Container.Nested nest = new Container.Nested();
嵌套类型的 class 的访问属性可为:public, protected, internal, protected internal, private, private protected
在 sealed class(封闭类)中声明 protected, protected internal, private protected 的嵌套类,会引起 CS0628 编译警告
嵌套类型的 struct 的访问属性可为:public, internal, private