小鸡问母鸡:可否不用下蛋,带我出去玩啊?母鸡道:不行,我要工作!小鸡说:可你已经下了这么多蛋了!母鸡意味深长地对小鸡说:一天一个蛋,菜刀靠边站,一月不生蛋,高压锅里见。
存在是因为你创造价值,淘汰是因为你失去价值。过去的价值不代表未来,所以每天都要努力!
========================手动分割线==========================
一、接口
- 接口使用interface关键字表示,可以有方法、属性、事件、索引器这四种成员类型
- 使用场景:接口就是为了解决不能继承多个基类的问题
- 接口只负责类的声明,保证统一
1.1 接口的定义:
- 在nameSpace中添加如下代码:
interface USB
{
//不能包含字段
//string name;
float Type { get; set; }
void Read ();
}
1.2 接口的特性:
- 1.接口可以包含方法和属性的声明,但不能包含字段
- 2.接口中所有方法、属性默认为public,不能再添加修饰符
- 3.实现接口的任何类或者结构必须实现其所有成员的方法
- 4.接口不能直接实例化,但是可以通过指向子类间接实例化
- 5.类或结构可以实现多个接口。类可以继承基类并实现一个或多个接口
1.3 接口的使用
class Upan:USB
{
public float Type { get; set; }
public void Read ()
{
Console.WriteLine ("我是U盘");
}
}
class Ypan:USB
{
public float Type { get; set; }
public void Read ()
{
Console.WriteLine ("我是硬盘");
}
}
- 在Main方法中添加如下代码
// 1.4 接口的实例化及子类的使用 -- 通过子类进行实例化
USB usb = new Upan ();
usb.Read ();
usb = new Ypan ();
usb.Read ();
1.5 接口的多重继承
- 接口继承:和类继承不一样,首先类的继承不仅是继承说明而且也是继承实现,但接口只是继承说明
- 接口可以从零个或者多个接口中继承,从多个接口中继承时用 , 隔开
- 具有多重继承的类,必须实现所有接口中的方法
- 在nameSpace中添加如下代码
interface IProgram
{
void Fun ();
}
interface IAProgram : IProgram
{
void Func ();
}
class AProgram:IAProgram
{
// 这里使用到了多重继承,该类就必须实现所有接口中的方法
public void Func ()
{
Console.WriteLine ("第二个");
}
public void Fun ()
{
Console.WriteLine ("第一个");
}
}
- 在Main方法中添加如下代码
IProgram ip1 = new AProgram ();
ip1.Fun ();// 只能调用第一个接口中声明的方法
IAProgram ip = new AProgram ();
ip.Fun ();
ip.Func ();// 可以调用第二个接口和第二个接口继承过来的方法
1.6 接口和抽象类
相同点:
1> 两者都定义了一些未实现的属性和方法,所有继承它们的类都继承这些成员;
2> 两者都包含可以由子类继承的抽象成员
3> 两者都不能直接实例化不同点:
1> 抽象类中除了拥有抽象成员之外,还可以拥有非抽象成员,而接口所有的成员都是抽象的
2> 抽象类的成员可以是私有的,而接口成员默认是共有的
3> 接口中不能包含构造函数,析构函数,静态成员和常量
4> C#只支持单继承,也就是子类只有一个父类,而一个子类却可以实现多个接口,而且接口可以多继承
练习:创建IArea和IVolume接口,创建Ball类实现这两个接口,并实现计算球面积area和球体积volume。
- 在nameSpace中添加如下代码
interface IArea
{
void Area ();
}
interface IVolume
{
void Volume ();
}
class Ball:IVolume, IArea
{
double radius;
public Ball (double radius)
{
this.radius = radius;
}
public void Area ()
{
double area = 4 * Math.PI * radius * radius;
Console.WriteLine ("球的面积为:" + area);
}
public void Volume ()
{
double volume = (4 / 3) * Math.PI * radius * radius * radius;
Console.WriteLine ("球的体积为:" + volume);
}
}
在Main方法中添加如下代码
// 直接实例化一个子类的对象
Ball ball = new Ball (2);
ball.Area ();
ball.Volume ();
二、泛型
- C#中的泛型可以将类型作为参数来传递,即在创建类型时,用一个特定的符号 如“T”来表示一个占位作用来替换实际类型,等待实例化的时候用一个实际类型去替换,这样就可以由外界来控制所需参数的类型。
- 优点:
1.使用泛型可以最大限度的重用代码,保护类型的安全以及提高性能
2.降低了强制转换或装箱操作的成本或风险。
3.可以对泛型类进行约束以访问特定数据类型的方法 - 缺点:
泛型成员因类型不确定,可能是类、结构体、字符、枚举...所以不能使用算术运算符、比较运算符等进行运算!
- 注意:可以使用赋值运算符
- 泛型的定义
public class Text// 使用<占位符>来表示一个待定的数据类型
{
public void text (R a, R b)
{
Console.WriteLine (a + "哈哈哈哈哈哈" + b);
}
}
- 在Main方法中添加如下代码
// 泛型的使用
// 使用int类型来替换占位符R,表示实际的数据类型,实参需要给int类型
Text t = new Text ();
t.text (2, 5);
三、泛型类型多参数
- 注意:
1.类型参数并不是只有一个,可以有多个。
2.类型参数可以是编译器识别的任何类型。
3.类型参数的名字不能随便起,不能重名。
- 在NameSpace命名空间下添加:
public class Test
{
public void test (T a, U b)
{
Console.WriteLine (a + "come here" + " " + b);
}
}
- 在Main方法中添加如下代码讲解多参数的泛型
Test tt = new Test ();
tt.test (3, "pangzi");
练习: 定义一个函数,交换两个数的值
- 在命名空间中添加如下代码
class ExchangeValue
{
public void SwapValue (ref T a, ref T b)
{
T temp = a;
a = b;
b = temp;
}
}
- 在Main方法中添加如下代码讲解多参数的泛型
ExchangeValue change = new ExchangeValue ();
float a = 3.1f, b = 5.1f;
change.SwapValue (ref a, ref b);
Console.WriteLine ("a = {0}, b = {1}", a, b);
3.1 泛型类型参数的 约束
- 目的:为了限制传入参数的数据类型,对泛型数据类型进行限制。
- 如果客户端代码尝试使用某个约束所不允许的类型来实例化类,则会产生编译时错误
第一种形式:规定系统数据类型
class -- 值类型
要求泛型参数必须是值类型,如int、float、double...struct -- 引用类型
要求泛型参数必须是引用类型,如string、object、class、delegate、数组...第二种形式:规定自定义类或接口
要求泛型参数必须是给定的类及其子类或接口
//引用类型案例
class ATest where T : class
{
public void Test (T a)
{
Console.WriteLine ("a = " + a);
}
}
- 在Main方法中添加如下代码讲解多参数的泛型
//ATest aa = new ATest ();//这里传入int会报错
ATest a = new ATest ();
a.Test ("hehe");
- 在命名空间中添加如下代码
class BTest where T : struct
{
public void Test (T b)
{
Console.WriteLine ("b = " + b);
}
}
- 在Main方法中添加如下代码讲解多参数的泛型
BTest b = new BTest ();
b.Test (3);
- 在命名空间中添加如下代码来讲解自定义类的泛型约束
class Person
{
public string Name { get; set; }
}
class Laowang : Person
{
}
// 泛型类型参数的约束 -- 继承
class CTest where T : Laowang
{
public void Test (T a)
{
Console.WriteLine ("a = " + a.Name);
}
}
- 在Main方法中添加如下代码讲解多参数的泛型
Laowang lw = new Laowang ();
lw.Name = "老王";
CTest c = new CTest ();
c.Test (lw);
四、泛型类和泛型方法
- 将泛型作用于一个类中,用于指代不确定的数据类型
- 在命名空间中添加如下代码来讲解自定义类的泛型约束
// 泛型类的继承
class BaseClass
{
public void BasePrint (T a)
{
Console.WriteLine ("a = " + a);
}
}
class SubClass : BaseClass
{
}
- 在Main方法中添加如下代码讲解泛型类的继承
SubClass sub = new SubClass ();
sub.BasePrint (44);
练习: 定义MyList类,该类模拟一个动态数组,可以用来存放数据(以int为例)
1)定义属性Count,用来记录元素个数
2)定义添加元素的方法
3)定义插入元素的方法
4)定义输出全部元素的个数
- 在命名空间中添加如下代码来讲解自定义类的泛型约束
class MyList:List
{
// 定义属性Count
public int count {
get {
return this.Count;
}
}
// 添加
public void add (T a)
{
this.Add (a);
}
// 插入
public void insert (T a, int index)
{
this.Insert (index, a);
}
// 输出
public void output ()
{
foreach (T temp in this) {
Console.WriteLine (temp);
}
}
// 泛型方法:泛型也可以作用于方法中(这个在****之后再写)
public void ExchangeValue (ref R a, ref R b)
{
R temp = a;
a = b;
b = temp;
}
}
- 在Main方法中添加如下代码讲解泛型类的继承
MyList list = new MyList ();
list.add (1);
list.add (2);
Console.WriteLine (list.count);
list.insert (0, 0);
Console.WriteLine (list.count);
list.output ();
MyList strList = new MyList ();
strList.add ("hanzi");
strList.add ("meizi");
Console.WriteLine (strList.count);
strList.output ();
- 泛型方法:泛型也可以作用于方法中(方法在上面)
- 在Main方法中添加如下代码进行验证
int x = 2, y = 5;
strList.ExchangeValue (ref x, ref y);
Console.WriteLine ("x = {0}, y = {1}", x, y);
这里也可以换成float、double、string或者其他类型)
string p = "haha", q = "hehe";
strList.ExchangeValue (ref p, ref q);
Console.WriteLine (p + " " + q);
本次讲解就到这里,有关技术问题请小伙伴们添加QQ群:941928511,大家一起探讨!
版权声明:本文为博主原创文章,转载请附上原文出处链接和本声明