成员定义
修饰符 | 含义 |
---|---|
public | 可以由任意代码访问 |
无 或 private | 只能由类中的的代码访问,默认关键字 |
internal | 只能由定义它的程序集(项目)内部的代码访问 |
protected | 由类或派生类中的代码访问 |
protected internal | 只能由程序集中派生类的代码访问 |
- static,类成员,而非实例成员;可有于定义字段、属性、方法
- const,用于定义常量,通过类直接访问
- readonly,用于定义变量,只能由构造函数赋值或定义变量时初始化赋值
定义字段
- 公共字段以 PascalCasing 形式定义,私有字段推荐以 pascalCasing 形式定义
class MyClass
{
public int MyInt;
int myString;
public readonly double MyDouble = 20.32D;
public static float MyFloat = 3.14F;
const float PI = 3.1415926F;
}
定义方法
- 公共方法以 PascalCasing 形式定义
- 以 static 定义的方法,只能过类访问
修饰符 | 含义 |
---|---|
virtual | 方法可以重写 |
abstract | 方法必须在非抽象派生类中重写(只能用于抽象类中) |
override | 方法重写一个基类方法(重写方法时,必须用此关键字) |
extern | 方法定义放在其它地方 |
public class MyBaseClass
{
// virtual 基类定义可重写
public virtual void DoSomething()
{
// Base implementation.
}
}
public class MyDerivedClass : MyBaseClass
{
// override 派生类实现了重写
public override void DoSomething()
{
// Derived class implementation, override base implementation.
}
}
public class MyDerivedClass1 : MyBaseClass
{
// override 派生类实现了重写,sealed 但指出其子类不能再重写
public sealed override void DoSomething()
{
// Derived class implementation, override base implementation.
}
}
定义属性
-
公共属性以 PascalCasing 形式定义
-
至少包含 get 或者 set
-
get 必须有返回值,类型为属性类型,一般与私有这段关联
-
不能同时为 get 与 set 指定访问控制
-
get 与 set 的访问控制要比属性本身严格
-
set 中通过 value 关键字来给字段赋值
-
可以 set 中编写值校验来决定是否执行赋值
-
4种处理 set 校验失败后,不赋值的策略(推荐 3 与 4)
- 什么也不做
- 给字段赋默认值
- 继续执行,但记录下该事件
- 抛出异常
private int myInt;
public int MyInt { get => myInt; set => myInt = value; }
// 只有 get 没有 set
private int myDoubledInt = 2;
public int MyDoubledIntProp => (myDoubledInt * 2);
重构成员
编写字段后,通过代码编辑器由系统自动生成属性
private string stringHello;
public string StringHello { get => stringHello; set => stringHello = value; }
自动属性
不定义字段,由编译器自动生成。
- 只能通过属性访问,因为字段由系统生成,不知道名字
public string StringHello = {
get;
set;
}
public string StringHello = { get; set; }
// 只有 get 的自动属性
public string StringHello = { get; }
// 自动属性初始化
public string StringHello = { get; } = "Hello";
类成员的其他主题
隐藏基类方法
- 隐藏用 new , 重写用 override
- 无论基类是否使用 virtual 定义,都可以用 new 来隐藏
- 派生类虽然隐藏了基类的方法,但仍可以通过基类来调用
public class MyBaseClass
{
public void DoSomething()
{
// Base implementation.
}
}
// 系统会发警告,提示隐藏一个基类成员
public class MyDerivedClass : MyBaseClass
{
public void DoSomething()
{
// Derived Class implementation,hides base implementation.
}
}
// 采用 new 强制隐藏
public class MyDerivedClass : MyBaseClass
{
new public void DoSomething()
{
// Derived Class implementation,hides base implementation.
}
}
调用重写或隐藏的基类方法
- 派生类中通过 base 来调用隐藏了的基类方法
public class MyBaseClass
{
public virtual void DoSomething()
{
// Base implementation.
}
}
public class MyDerivedClass : MyBaseClass
{
public override void DoSomething()
{
base.DoSomethind();
// Derived Class implementation,hides base implementation.
}
}
this
- 表示对当前对象的引用
- 不能在 static 成员中使用 this
- 最常用的功能:将当前对象实例的引用传递给一个方法;限制局部类型的成员。
// 将当前对象实例的引用传递给一个方法
public void doSomething()
{
MyTargetClass myObj = new MyTargetClass();
myObj.DoSomethingWith(this);
}
// 限定局部类型的成员
public class MyClass
{
private int someData;
public int SomeData
{
get
{
return this.comeData;
}
}
}
嵌套的类型定义
// 定义
public class ClassC
{
public class ClasssD
{
public override string ToString()
{
return "D";
}
}
}
// 使用
ClassC.ClasssD myC = new ClassC.ClasssD();
Console.WriteLine(myC.ToString());
- 私有嵌套类,可以阻止空间内其他成员对其的访问
- 嵌套类可以访问其包含类的私有和受保护成员
// 定义
public class ClassA
{
private int state = -1;
public int State
{
get { return state; }
}
public class ClassB
{
public void SetPrivateState(ClassA target, int newState)
{
target.state = newState;
}
}
}
// 使用
ClassA myObject = new ClassA();
Console.WriteLine($"myObject.State = {myObject.State}");
ClassA.ClassB myOtherObject = new ClassA.ClassB();
myOtherObject.SetPrivateState(myObject, 999);
Console.WriteLine($"myObject.State = {myObject.State}");
// 结果
myObject.State = -1
myObject.State = 999
接口的实现
- 所有接口成员都是隐式公共(public)的,不能使用访问修饰符(public/private/protected/internal都不行)
- 接口成员不能包含实现代码
- 接口成员不能定义字段成员
- 不能使用 static/virtual/abstract/sealed 来定义接口成员
- 禁止类型定义成员
- 可以使用 new 来隐藏基类成员
- 至少定义属性的 get 与 set 存取器中的一个
- 接口可以被定义为类成员,但不能定义为其他接口的成员
// 隐藏
interface IMyBaseInterface
{
void DoSomething();
}
interface IMyDerivedInterfalce : IMyBaseInterface
{
new void DoSomething();
}
// 属性
interface IMyInterface
{
int MyInt { get; set; }
}
在类中实现接口
- 实现接口的类必须包含该接口所有成员的实现代码,必须是公共的,属性必须匹配指定的 get 与 set
- 可以使用 virtual 与 abstract 来实现接口成员,但不能使用 static 或 const
// 实现接口定义
interface IMyInterface
{
void DoSomething();
void DoSomethingElse();
}
public class MyClass : IMyInterface
{
void DoSomething() {
// 实现
}
void DoSomethingElse() {
// 实现
}
}
// 隐式实现
interface IMyInterface
{
void DoSomething();
void DoSomethingElse();
}
class MyBaseClass
{
public void DoSomething() {} // 注意必须是 public
}
class MyDerivedClass : MyBaseClass, IMyInterface
{
// 隐式已实现 DoSomething()
public void DoSomethingElse() {}
}
// 重写
public interface IMyInterface
{
void DoSomething();
void DoSomethingElse();
}
class MyBaseClass : IMyInteface
{
public virtual void DoSomething() {}
public virtual void DoSomethingElse() {}
}
// 版本1
class MyDerivedClass : MyBaseClass
{
public override void DoSomething() {}
public override void DoSomethingElse() {}
}
// 版本1调用
IMyInteface myInteface = myClass;
myInteface.DoSomething();
myInteface.DoSomethingElse();
// 版本1结果
// MyDerivedClass 的 DoSomething 与 DoSomethingElse 方法
// 版本2
class MyDerivedClass : MyBaseClass
{
public new void DoSomething() {}
public new void DoSomethingElse() {}
}
// 版本2调用
IMyInteface myInteface = myClass;
myInteface.DoSomething();
myInteface.DoSomethingElse();
// 版本2结果
// MyBaseClass 的 DoSomething 与 DoSomethingElse 方法
显示实现接口成员
只能通过接口来访问,不能通过类来访问
public interface IMyInterface
{
void DoSomething();
void DoSomethingElse();
}
public class MyClass : IMyInterface
{
void IMyInterface.DoSomething() {} // 显示实现接口成员
public void DoSomethingElse() {} // 隐式实现接口成员
}
MyClass myClass = new MyClass();
myClass.DoSomething() // 报错
myClass.DoSomethingElse();
IMyIntefalce myIntefalce = myClass;
myIntefalce.DoSomething(); // 只能通过此种方式来访问
myIntefalce.DoSomethingElse();
其它属性存取器
对于隐式实现接口时,在接口中定义属性时只实现了 get 或 set 时,可以在类中添加另外的 get 或 set
public interface IMyInterface
{
int MyIntProperty { get; }
}
// 版本1
public class MyClass1 : IMyInterface
{
public int MyIntProperty { get ; set; // 添在没有在接口中实现的 set }
}
MyClass1 myClass = new MyClass1();
myClass.MyIntProperty = 100;
IMyInterface myInterface = myClass;
int myInt = myInterface.MyIntProperty ;
myInterface.MyIntProperty = 200; // 报错,因为是在派生类中实现的
版本2
public class MyClass1 : IMyInterface
{
public int MyIntProperty { get ; protected set; // 只能在类及派生类中访问 }
}
MyClass1 myClass = new MyClass1();
myClass.MyIntProperty = 100; // 报错
部分类定义
- 通过 #region 来在代码编辑器折叠代码,使代码更容易阅读
- 使用 partial 关键字,将类的定义分散在多个文件中
- partial 必须出现在每个文件中类定义的相同部分
- 多个部分类也只能有一个基类
- 多个部分类实现的不同接口,最后编译时会合并在一起
// region
public Myclass
{
#region Fields
private int myInt;
#endregion
...
#region Methods
public void DoSomething()
{
// Do something ...
}
#endregion
}
// partial
public partial class MyClass : MyBaseClass, MyInterface1 {}
public partial class MyClass : MyBaseClass, MyInterface2 {}
// 等价于
public class MyClass : MyBaseClass, MyInterface1, MyInterface2 {}
部分方法定义
- 部分方法使用 partial 关键字定义
- 在一个部分类中定义部分方法,但没有方法体,在另一个部分类中实现方法体
- 部分方法可以是静态的,但总是私有的,且不能有返回值
- 部分方法的参数,不能是 out ,可以是 ref
- 部分方法不能使用 virtual, abstract, override, new, sealed, extern 修辞符
- 部分类的作用体现在编译代码时,而不是使用代码时
- 代码编译时,如果代码中发现一个未实现的部分方法,会直接删除此方法及相关的引用,优化性能
// 部分方法
public partial class MyClass
{
partial void MyPartialMethod(); // 此处定义
}
public partial class MyClass
{
partial void MyPartialMethod()
{
// Method implementation,此处实现
}
}
// 调用未实现的部分类
public partial class MyClass
{
partial void DoSomethingElse();
public void DoSomething() {
Console.WriteLine("DoSomething 开始");
DoSomethingElse(); // 调用部分方法
Console.WriteLine("DoSomething 结束")
}
}
public partial class MyClass
{
// 此没有实现 DoSomethingElse 方法
}
// 输出结果
DoSomething 开始
DoSomething 结束