class X {…}
var instance = new X(…);
C#中,数据成员称为字段。与具体对象相关的字段称为实例字段;实例字段允许在声明时初始化,初始化语句在类构造函数前执行, 例如:
class Employee
{
public string FirstName;
public string LastName;
public string Salary = "Not enough";
public Employee()
{
Salray= string.Empty;
}
}
实例字段只能从对象中访问,例如:
public static void Main()
{
Employee employee1 = new Employee();
Employee employee2;
employee2 = new Employee();
employee1.FirstName = "Inigo";
employee1.LastName = "Montoya";
employee1.Salary = "Too Little";
IncreaseSalary(employee1);
Console.WriteLine( "{0} {1}: {2}",employee1.FirstName, employee1.LastName,employee1.Salary);
}
static void IncreaseSalary(Employee employee)
{
employee.Salary = "Enough to survive on";
}
C#中, 只能通过对象调用的成员方法称为实例方法。
在类的实例成员内部,可以使用this 获得调用实例成员的对象引用,例如:
class Employee
{
public string FirstName;
public string LastName;
public string Salary;
public string GetName()
{
return $"{ FirstName } { LastName }";
}
public void SetName(string newFirstName, string newLastName)
{
this.FirstName = newFirstName;
this.LastName = newLastName;
}
}
this关键字也能用来显式调用实例方法 或在方法调用中传递 ,例如:
class Employee
{
public string FirstName;
public string LastName;
public string Salary;
public string GetName() => $"{ FirstName } { LastName }";
public void SetName(string newFirstName, string newLastName)
{
this.FirstName = newFirstName;
this.LastName = newLastName;
Console.WriteLine( $"Name changed to '{ this.GetName() }'");
}
public void Save()
{
DataStorage.Store(this);
}
}
class DataStorage
{
// Save an employee object to a file named with the Employee name.
public static void Store(Employee employee) { ...}
}
访问修饰符标识了所修饰成员的封装级别。
class Employee
{
public string FirstName, LastName,Salary, Password;
private bool IsAuthenticated;
public bool Logon(string password)
{
if (Password == password)
IsAuthenticated = true;
return IsAuthenticated;
}
public bool GetIsAuthenticated() => IsAuthenticated;
// ...
}
类型缺省访问级别:
Members of | Default member accessibility | Allowed declared accessibility of the member |
enum | public | None |
class | private | public protected internal private protected internal |
interface | public | None |
struct | private | public internal private |
属性结合了字段和成员方法的特点。 对于对象的用户来说,属性似乎是一个字段,访问属性使用与访问字段 相同的语法。 对于类的实现者来说,属性是由 get 访问器和/或 set 访问器组成代码块。读取属性时,执行 get 访问器的代码块;向属性赋值时,执行 set 访问器的代码块。
不含 set 访问器的属性称为只读属性。 将不含 get 访问器的属性称为只写属性。同时具有以上两个访问器的属性称为读写属性。
与字段不同,属性不会被归类为变量。 因此,不能将属性作为 ref 或 out 参数传递。
在 C# 3.0及更高版本,当属性访问器中不需要任何其他逻辑时,自动实现的属性会使属性声明更加简洁。在 C# 6和更高版本中,可以像字段一样初始化自动实现属性。
public static void Main()
{
Employee employee1 = new Employee();
Employee employee2 = new Employee();
employee1.FirstName = "Inigo"; // Call the FirstName property's setter.
System.Console.WriteLine(employee1.FirstName); // Call the FirstName property's getter.
// Assign an auto-implemented property
employee2.Title = "Computer Nerd";
employee1.Manager = employee2;
// Print employee1's manager's title.
System.Console.WriteLine(employee1.Manager.Title);
}
class Employee
{
public string FirstName { get; set; }
private string LastName { get; set; }
public string Title { get; set; }
public Employee Manager { get; set; }
public string Salary { get; set; } = "Not Enough";
}
缺省情况下,get /set 访问器具有相同的可见性和访问级别。从C# 2.0开始,在属性实现中允许为get 或set 部分指定访问修饰符,从而覆盖为属性指定的访问修饰符
对属性 使用访问修饰符有以下限制:
class Employee
{
public void Initialize(int id) => Id = id.ToString();
public string Id
{
get
{
return _Id;
}
private set
{
// Providing an access modifier is possible in C# 2.0 and higher only
_Id = value;
}
}
private string _Id;
}
class Employee
{
public Employee(string firstName, string lastName) // constructor
{
FirstName = firstName;
LastName = lastName;
}
public string FirstName { get; set; }
public string LastName { get; set; }
public string Title {get; set}
public string Salary { get; set; } = "Not Enough";
public string Name
{
get
{
return FirstName + " " + LastName;
}
set
{
string[] names;
names = value.Split(new char[] { ' ' });
if (names.Length == 2)
{
FirstName = names[0];
LastName = names[1];
}
else
{
throw new System.ArgumentException(string.Format($"Assigned value '{ value }' is invalid", nameof(value)));
}
}
}
}
public static void Main()
{
Employee employee;
employee = new Employee("Inigo", "Montoya");
employee.Salary = "Too Little";
Console.WriteLine( "{0} {1}: {2}", employee.FirstName,
employee.LastName,employee.Salary);
}
如果类没有显式定义构造器,C# 编译器会在编译时自动添加一个不含任何参数的构造函数。一旦类显定义构造器,编译器就不会提供默认构造函数。
初始化器用于初始化对象中所有可以访问的字段和属性。在调用构造器时,可以在后面的大括号中添加成员初始化列表,例如:
public static void Main()
{
Employee employee = new Employee("Inigo", "Montoya")
{
Title = "Computer Nerd",
Salary = "Not enough"
};
Console.WriteLine("{0} {1} ({2}): {3}", employee.FirstName, employee.LastName, employee.Title, employee.Salary);
}
C# 中,允许从一个构造器中调用同一个类的另一个构造器, 方法是在一个冒号后添加this关键字,再添加被调用构造器的参数列表,例如:
class Employee
{
public Employee(string firstName, string lastName)
{
FirstName = firstName;
LastName = lastName;
}
public Employee(int id, string firstName, string lastName)
: this(firstName, lastName)
{
Id = id;
}
public Employee(int id)
{
Id = id;
// NOTE: Member constructors cannot be called explicitly inline
// this(id, firstName, lastName);
}
public int Id { get; private set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Salary { get; set; } = "Not Enough";
}
匿名类型是编译器动态生成的类型,编译器遇到匿名类型时,会自动生成一个CIL类。该类具有与匿名类型声明中已经命名的值和数据类型对应的属性。例如:
public static void Main()
{
var patent1 =new
{
Title = "Bifocals",
YearOfPublication = "1784"
};
var patent2 =new
{
Title = "Phonograph",
YearOfPublication = "1877"
};
var patent3 =new
{
patent1.Title,
Year = patent1.YearOfPublication
};
System.Console.WriteLine("{0} ({1})",patent1.Title, patent1.YearOfPublication);
System.Console.WriteLine("{0} ({1})", patent2.Title, patent1.YearOfPublication);
Console.WriteLine();
Console.WriteLine(patent1);
Console.WriteLine(patent2);
Console.WriteLine();
Console.WriteLine(patent3);
}
在类的多个实例之间共享的字段,用static 关键字标识。和实例字段一样,静态字段也可以在声明时初始化。例如:
class Employee
{
// ...
public static int Id; // default(int): 0
public static int NextId = 42;
// ...
}
和实例字段不一样,未初始化的静态字段将获得默认值,即 default(T)的结果
和静态字段类似,静态方法也用static关键字标识。静态方法可以通过类名直接访问。例如:
public static void Main()
{
DirectoryInfo directory = new DirectoryInfo(".\\Source");
directory.MoveTo(".\\Root");
DirectoryInfoExtension.CopyTo(directory, ".\\Target", SearchOption.AllDirectories, "*");
}
public static class DirectoryInfoExtension
{
public static void CopyTo( DirectoryInfo sourceDirectory, string target, SearchOption option, string searchPattern)
{
if (target[target.Length - 1] != Path.DirectorySeparatorChar)
target += Path.DirectorySeparatorChar;
if (!Directory.Exists(target))
Directory.CreateDirectory(target);
for (int i = 0; i < searchPattern.Length; i++)
{
foreach (string file in Directory.GetFiles(sourceDirectory.FullName, searchPattern))
{
File.Copy(file, target + Path.GetFileName(file), true);
}
}
if (option == SearchOption.AllDirectories) //Copy subdirectories (recursively)
{
foreach (string element in Directory.GetDirectories(sourceDirectory.FullName))
Copy(element, target + Path.GetFileName(element),searchPattern);
}
}
private static void Copy(string element, string fileName, string searchPattern)
{
Console.WriteLine("Copying " + fileName);
}
}
静态构造器不显式调用,而是在运行时在首次访问类时自动调用。首次访问类发生在条用普通构造器时,也可能发生在访问类的静态方法或字段。静态构造器不允许带任何参数
class Employee
{
static Employee()
{
Random randomGenerator = new Random();
NextId = randomGenerator.Next(101, 999);
}
// ...
public static int NextId = 42;
// ...
}
属性也能static。例如:
class Employee
{
// ...
public static int NextId
{
get
{
return _NextId;
}
private set
{
_NextId = value;
}
}
public static int _NextId = 42;
// ...
}
C#中也能定义静态类。静态类不含任何实例字段或方法。因此静态类不能实例化。编译器自动在CIL 代码中将静态类标记为abstract 和sealed。即将类指定为不可扩展
public static class SimpleMath
{
public static int Max(params int[] numbers)
{
if (numbers.Length == 0) // Check that there is at least one item in numbers.
throw new ArgumentException( "numbers cannot be empty", nameof(numbers));
int result = numbers[0];
foreach (int number in numbers)
{
if (number > result)
result = number;
}
return result;
}
}
public class Program
{
public static void Main(string[] args)
{
int[] numbers = new int[args.Length];
for (int count = 0; count < args.Length; count++)
numbers[count] = args[count].Length;
Console.WriteLine( $@"Longest argument length = { SimpleMath.Max(numbers) }");
}
}
class ConvertUnits
{
public const float CentimersPerInch = 2.54F;
public const int CupsPerGallon = 16;
}
readonly 修饰符只能用于字段(不能用于局部变量)。它指出字段值只能从构造器中更改或声明时通过初始化器更改。
class Employee
{
public Employee(int id)
{
_Id = id;
}
private readonly int _Id;
public int Id{
get { return _Id; }
}
// Error: A readonly field cannot be assigned to (excep in a constructor or a variable initializer)
// public void SetId(int id) =>_Id = id;
}
分部类是一个类的多个部分, 这些部分可以合并成一个完整的类。分部类主要用于将一个类的定义划分到多个文件中。 C# 使用关键字partial来声明分部类
// File: Program1.cs
partial class Program
{
}
// File: Program2.cs
partial class Program
{
}
分部方法存在于分部类中,它允许在一个文件中声明方法,而在另一文件中实现该方法。例如:
// File: Person.Designer.cs
public partial class Person
{
#region Extensibility Method Definitions
partial void OnLastNameChanging(string value);
partial void OnFirstNameChanging(string value);
#endregion
// ...
}
// File: Person.cs
partial class Person
{
partial void OnLastNameChanging(string value)
{
//...
}
partial void OnFirstNameChanging(string value)
{
//...
}
}