C#面向对象类的简议
类
就.net平台而言,最基本的编程结构就是类类型。
类是由字段数据(通常叫成员或者变量)和操作这些数据的成员(函数、属性、事件、方法)所构成的自定义类型。
字段数据用来表示类的实例(或称为对象)的“状态”。
通过将数据和相关功能集合在类定义中,我们就可以仿照现实生活中的实体来设计软件。
- 通过New 关键字 创建对象,将对象分配到内存中。
- 构造函数和默认构造函数
- 对象用户通常希望用户在使用对象之前献给对象的字段数据赋相关值。通过NEW进行间接调用。
- C# 默认内建了一个贡藕早函数,它允许创建对象的时候创建其状态,默认狗仔函数不解释偶惨呼, 乌返回值,确保所有字段数据都设置为正确的默认值。
- This 解决了当传入参数和这个类的数据字段重名时造成的作用域歧义。提供对当前对象的访问。
- 使用This串联构造函数
- static 静态数据和非静态数据
静态数据,同一类别的所有对象都会共享内存。
非静态数据就会每个对象一个副本, 相会之间不影响。
class SavingsAccount
{
// Instance level data. 非静态数据
public double currBalance;
// A static point of data. 静态数据
public static double currInterestRate;
public static double InterestRate
{
get { return currInterestRate; }
set { currInterestRate = value; }
}
public SavingsAccount( double balance )
{
currBalance = balance;
}
// A static constructor!
static SavingsAccount()
{
Console.WriteLine("In static ctor!");
currInterestRate = 0.04;
}
// Static members to get/set interest rate.
public static void SetInterestRate( double newRate )
{ currInterestRate = newRate; }
public static double GetInterestRate()
{ return currInterestRate; }
}
静态方法
静态构造函数
静态构造函数的执行先于任何实列级别的构造函数。
静态构造函数不接受参数和修饰符。
静态构造函数只执行一次。
静态类
OOP的三大支柱
一、 封装 encapsulation
- 核心的概念是对象内部的数据不应该从实例直接访问。
- 对象的数据应该定义为私有的,如果调用者想改变对象的状态,就要间接使用公共成员。
- 提供了一种保护状态数据完整性的方法。
- 封装的形式-- 使用属性封装数据–使用单个命名的项来控制内部数据点。
项目 | Value |
---|---|
method | Get / Set Method |
访问器 | Accessor (get method)/Mutator (set method) |
Properties | Properties , Automatic properties! public string PetName { get; set; } |
class Employee
{
// Field data.
private string empName;
private int empID;
private float currPay;
private int empAge;
#region Constructors
public Employee() { }
public Employee( string name, int id, float pay )
: this(name, 0, id, pay) { }
public Employee( string name, int age, int id, float pay )
{
// Better! Use properties when setting class data.
// This reduces the amount of duplicate error checks.
Name = name;
Age = age;
ID = id;
Pay = pay;
}
#endregion
#region Methods
public void GiveBonus( float amount )
{
currPay += amount;
}
public void DisplayStats()
{
Console.WriteLine("Name: {0}", Name);
Console.WriteLine("ID: {0}", ID);
Console.WriteLine("Age: {0}", Age);
Console.WriteLine("Pay: {0}", Pay);
}
#endregion
#region Get / Set Method
// Accessor (get method) 访问器
public string GetName()
{
return empName;
}
// Mutator (set method)
public void SetName( string name )
{
// Do a check on incoming value
// before making assignment.
if (name.Length > 15)
Console.WriteLine("Error! Name must be less than 15 characters!");
else
empName = name;
}
#endregion
#region Properties
// Properties!
public string Name
{
get { return empName; }
set
{
if (value.Length > 15)
Console.WriteLine("Error! Name must be less than 16 characters!");
else
empName = value;
}
}
// We could add additional business rules to the sets of these properties,
// however there is no need to do so for this example.
public int ID
{
get { return empID; }
set { empID = value; }
}
public float Pay
{
get { return currPay; }
set { currPay = value; }
}
public int Age
{
get { return empAge; }
set { empAge = value; }
}
#endregion
}
namespace AutoProps
{
#region Car class with automatic properties
class Car
{
// Automatic properties!
public string PetName { get; set; }
public int Speed { get; set; }
public string Color { get; set; }
public void DisplayStats()
{
Console.WriteLine("Car Name: {0}", PetName);
Console.WriteLine("Speed: {0}", Speed);
Console.WriteLine("Color: {0}", Color);
}
}
#endregion
#region Garage class
class Garage
{
// The hidden int backing field is set to zero!
public int NumberOfCars { get; set; }
// The hidden Car backing field is set to null!
public Car MyAuto { get; set; }
// Must use constructors to override default
// values assigned to hidden backing fields.
public Garage()
{
MyAuto = new Car();
NumberOfCars = 1;
}
public Garage( Car car, int number )
{
MyAuto = car;
NumberOfCars = number;
}
}
#endregion
class Program
{
static void Main( string[] args )
{
Console.WriteLine("***** Fun with Automatic Properties *****\n");
// Make a car.
Car c = new Car();
c.PetName = "Frank";
c.Speed = 55;
c.Color = "Red";
c.DisplayStats();
// Put car in the garage.
Garage g = new Garage();
g.MyAuto = c;
Console.WriteLine("Number of Cars in garage: {0}", g.NumberOfCars);
Console.WriteLine("Your car is named: {0}", g.MyAuto.PetName);
Console.ReadLine();
}
}
二、继承 inherit
继承财产 inherit property;
他是基于已与类定义来创建新类定义语言的能力。
本质上,通过继承,子类可以继承基类核心功能,并扩展基类的行为。
代码的重用分为两个部分:
- 继承 is-a 关系
IS-A表示继承。父类与子类,具有很高的耦合度。
class Manager : Employee
- 包含/委托 has-a 关系
HAS-A表示组合。是整体与部分的关系,同时它们的生命周期都是一样的。
public class Driver {
private String name;
private String number;
private int drinkStatus;
}
public class Car {
private String number;
private int speed;
private Driver driver;
}
分别有一个司机类和一个车辆类,车辆类有一个属性是司机类型的属性,这就表示了车辆类包含了司机类。
- use-a
- 表示使用关系,依然是其中一个拥有另外一个,但是不负责销毁,也就是声明周期不一样。
`public class Police {
public void check(Car car){
if(car.getSpeed() > 100){
System.out.println("车辆超速,被拦截。车牌号:"
+car.getNumber()
+";司机姓名:"
+car.getDriver().getName()
+";驾照号:"
+car.getDriver().getNumber()
+";罚款2000,扣6分");
if(car.getDriver().getDrinkStatus() == 1){
System.out.println("发现司机处于饮酒状态,追加罚款5000,拘留12天,扣12分");
}
}else{
System.out.println("未超速,放行");
}
}
}
`
有一个警察类,他有一个临检的方法,这个方法要输入一个车辆类型的参数,这就是use-a的关系。
IS-A 用于继承
一般我们认为继承可以分为两种基本的形式:实现继承和接口继承。
实现继承的主要目标是代码重用:
我们发现类B和类C存在同样的代码,因此我们设计了一个类A,用于存放通用的代码。
HAS-A;聚合关系,拥有关系;
类A中有B类型的成员引用变量。则类A“HAS-A”(拥有)类B、
例如;
列子;汽车拥有轮胎。(有关于私有成员变量的访问在截图中也有。)
三个类,主类,汽车类,轮胎类。
汽车类中有成员轮胎。
USES-A;依赖关系。
类A的方法操作了类B(对象)的成员。则称之为类A“USES-A”(用到了)类B。
例如,
例子;汽车在启动前检查汽油是否足够。
两个类 ,一个是汽车类,一个是主类(包含main方法的类);
启动要求,汽油量,两个成员,应该都在汽车类中。
因此,就是主类用到了汽车类。
————————————————
三、多态 polymorphic
Virtual和Override
虚方法和重写
abstract 抽象类
抽象类不能实例化。
NEW关键字可以遮蔽基类相同的方法名称。
基类/派生类的转换规则
隐式转换
显示转换
as/is 类型检查
// The abstract base class of the hierarchy.
abstract class Shape
{
public Shape( string name = "NoName" )
{ PetName = name; }
public Shape() {}
public string PetName { get; set; }
// A single virtual method.
// Force all child classes to define how to be rendered. 强制所有子类定义如何呈现。
public abstract void Draw();
}
// Circle DOES NOT override Draw().
// If we did not implement the abstract Draw() method, Circle would also be
// considered abstract, and would have to be marked abstract!
class Circle : Shape
{
public Circle() { }
public Circle( string name ) : base(name) { }
public override void Draw()
{
Console.WriteLine("Drawing {0} the Circle", PetName);
}
}
// Hexagon DOES override Draw().
class Hexagon : Shape
{
public Hexagon() { }
public Hexagon( string name ) : base(name) { }
public override void Draw()
{
Console.WriteLine("Drawing {0} the Hexagon", PetName);
}
}
// This class extends Circle and hides the inherited Draw() method.
class ThreeDCircle : Circle
{
// Hide the PetName property above me.
public new string PetName { get; set; }
// Hide any Draw() implementation above me.
public new void Draw()
{
Console.WriteLine("Drawing a 3D Circle");
}
}
static void Main( string[] args )
{
Console.WriteLine("***** Fun with Polymorphism *****\n");
// Make an array of Shape-compatible objects.
Shape[] myShapes = {new Hexagon(), new Circle(), new Hexagon("Mick"),
new Circle("Beth"), new Hexagon("Linda")};
// Loop over each item and interact with the
// polymorphic interface.
foreach (Shape s in myShapes)
{
s.Draw();
}
// This calls the Draw() method of the ThreeDCircle.
ThreeDCircle o = new ThreeDCircle();
o.Draw();
// This calls the Draw() method of the parent!
((Circle)o).Draw();
Console.ReadLine();
}
接口
- 接口可以被定义为抽象成员的集合。
- 因为接口不提供任何实现细节,通常把接口看做某个类型或者结构支持的行为。
- 如果两个或者更多类实现相同的接口,我们就可以以相同方式对待两个类型(又叫基于接口的多态),即使类型定义在独立的类继承体系中。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CustomInterface
{
// Models the ability to render a type in stunning 3D.建模以惊人的3D渲染类型的能力。
public interface IDraw3D
{
void Draw3D();
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CustomInterface
{
// This interface defines the behavior of "having points."
/*
public interface IPointy
{
// Implicitly public and abstract.
byte GetNumberOfPoints();
}
*/
// The pointy behavior as a read-only property.
public interface IPointy
{
// A read-write property in an interface would look like:
// retType PropName { get; set; }
// while a write-only property in an interface would be:
// retType PropName { set; }
//接口中的读写属性如下所示:
//retType属性名称{get;set;}
//而接口中的仅写属性将是:
//retType属性名称{set;}
byte Points { get; }
}
}
抽象基类和接口对比
- 接口有较高的多态性。(它可以被任何层次结构、任何命名空间活任何程序集中的任何类型活结构实现)
- 抽象类只有派生类才支持有抽象父类定义的成员
- 抽象类定义了一组抽象成员和构造函数、字段数据、非抽象成员等。接口只能包含抽象成员。
- 接口不能实例化因为他只是抽象成员的集合,所以我们不能像类和结构一样分配接口类型。
- 实现接口是一个要么全要要么全不要的命题。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CustomInterface
{
// The abstract base class of the hierarchy. 层次结构的抽象基类。
abstract class Shape
{
public Shape( string name = "NoName" )
{ PetName = name; }
public Shape() {}
public string PetName { get; set; }
// A single virtual method.
// Force all child classes to define how to be rendered.
//单个虚拟方法。
//强制所有子类定义如何呈现
public abstract void Draw();
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CustomInterface
{
// New Shape derived class named Triangle.
//名为Triangle的新Shape派生类。 三角形
class Triangle : Shape, IPointy
{
public Triangle() { }
public Triangle( string name ) : base(name) { }
public override void Draw()
{ Console.WriteLine("Drawing {0} the Triangle", PetName); }
// IPointy Implementation.
public byte Points
{
get { return 3; }
}
}
// Circle DOES NOT override Draw().
// If we did not implement the abstract Draw() method, Circle would also be
// considered abstract, and would have to be marked abstract!
//圆形不会覆盖Draw()。
//如果我们没有实现抽象的Draw()方法,Circle也将是
//被认为是抽象的,必须标记为抽象的!
class Circle : Shape
{
public Circle() { }
public Circle( string name ) : base(name) { }
public override void Draw()
{
Console.WriteLine("Drawing {0} the Circle", PetName);
}
}
// Hexagon now implements IPointy. Hexagon 六角形
class Hexagon : Shape, IPointy, IDraw3D
{
public Hexagon() { }
public Hexagon( string name ) : base(name) { }
public override void Draw()
{ Console.WriteLine("Drawing {0} the Hexagon", PetName); }
// IPointy Implementation.
public byte Points
{
get { return 6; }
}
public void Draw3D()
{
Console.WriteLine("Drawing Hexagon in 3D!");
}
}
// This class extends Circle and hides the inherited Draw() method.
//此类扩展Circle并隐藏继承的Draw()方法
class ThreeDCircle : Circle, IDraw3D
{
// Hide the PetName property above me.
//在我上方隐藏PetName属性。
public new string PetName { get; set; }
// Hide any Draw() implementation above me.
//在我上方隐藏任何Draw()实现。
public new void Draw()
{
Console.WriteLine("Drawing a 3D Circle");
}
public void Draw3D()
{ Console.WriteLine("Drawing Circle in 3D!"); }
}
}
测试代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CustomInterface
{
class Program
{
static void Main( string[] args )
{
Console.WriteLine("***** Fun with Interfaces *****\n");
// Make an array of Shapes.
Shape[] myShapes = { new Hexagon(), new Circle(),
new Triangle("Joe"), new Circle("JoJo")};
for (int i = 0; i < myShapes.Length; i++)
{
// Recall the Shape base class defines an abstract Draw()
// member, so all shapes know how to draw themselves.
//回想一下Shape基类定义了一个抽象的Draw()
//成员,所以所有形状都知道如何绘制自己。
myShapes[i].Draw();
// Who's pointy?
if (myShapes[i] is IPointy)
Console.WriteLine("-> Points: {0}", ((IPointy)myShapes[i]).Points);
else
Console.WriteLine("-> {0}\'s not pointy!", myShapes[i].PetName);
Console.WriteLine();
// Can I draw you in 3D?
if (myShapes[i] is IDraw3D)
DrawIn3D((IDraw3D)myShapes[i]);
}
// Get first pointy item.
// To be safe, you'd want to check firstPointyItem for null before proceeding.
//获取第一个尖头项。
//为了安全起见,您需要在继续之前检查firstPointyItem是否为null。
IPointy firstPointyItem = FindFirstPointyShape(myShapes);
Console.WriteLine("The item has {0} points", firstPointyItem.Points);
// This array can only contain types that
// implement the IPointy interface.
//此数组只能包含以下类型
//实现IPointy接口。
IPointy[] myPointyObjects = {new Hexagon(), new Knife(),
new Triangle(), new Fork(), new PitchFork()};
foreach (IPointy i in myPointyObjects)
Console.WriteLine("Object has {0} points.", i.Points);
Console.ReadLine();
}
static void DrawIn3D( IDraw3D itf3d )
{
Console.WriteLine("-> Drawing IDraw3D compatible type");
itf3d.Draw3D();
}
// This method returns the first object in the
// array that implements IPointy.
//此方法返回
//实现IPointy的数组。
static IPointy FindFirstPointyShape( Shape[] shapes )
{
foreach (Shape s in shapes)
{
if (s is IPointy)
return s as IPointy;
}
return null;
}
}
}
构建可枚举类型(IEnumerable和IEnmumrator)
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CustomEnumerator
{
// This seems reasonable...
public class Program
{
static void Main( string[] args )
{
Console.WriteLine("***** Fun with IEnumerable / IEnumerator *****\n");
Garage carLot = new Garage();
// Hand over each car in the collection?
foreach (Car c in carLot)
{
Console.WriteLine("{0} is going {1} MPH",
c.PetName, c.CurrentSpeed);
}
// Manually work with IEnumerator.
IEnumerator i = carLot.GetEnumerator();
i.MoveNext();
Car myCar = (Car)i.Current;
Console.WriteLine("{0} is going {1} MPH", myCar.PetName, myCar.CurrentSpeed);
Console.ReadLine();
}
}
}
方式一:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CustomEnumerator
{
// Garage contains a set of Car objects.
// 车库包含一组汽车对象
public class Garage : IEnumerable
{
private Car[] carArray = new Car[4];
// Fill with some Car objects upon startup.
public Garage()
{
carArray[0] = new Car("Rusty", 30);
carArray[1] = new Car("Clunker", 55);
carArray[2] = new Car("Zippy", 30);
carArray[3] = new Car("Fred", 30);
}
public IEnumerator GetEnumerator()
{
// Return the array object's IEnumerator.
return carArray.GetEnumerator();
}
}
}
方式二:使用Yield 关键字构建迭代器方法
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CustomEnumeratorWithYield
{
// Garage contains a set of Car objects.
public class Garage : IEnumerable
{
private Car[] carArray = new Car[4];
// Fill with some Car objects upon startup.
public Garage()
{
carArray[0] = new Car("Rusty", 30);
carArray[1] = new Car("Clunker", 55);
carArray[2] = new Car("Zippy", 30);
carArray[3] = new Car("Fred", 30);
}
public IEnumerator GetEnumerator()
{
foreach (Car c in carArray)
{
yield return c;
}
}
public IEnumerable GetTheCars( bool ReturnRevesed )
{
// Return the items in reverse.
if (ReturnRevesed)
{
for (int i = carArray.Length; i != 0; i--)
{
yield return carArray[i - 1];
}
}
else
{
// Return the items as placed in the array.
foreach (Car c in carArray)
{
yield return c;
}
}
}
}
}