接口
什么是接口
接口:接口是一组包含了类或结构可以实现的功能的定义。
接口的特性
1. 接口是一个引用类型,只包含了功能的定义,不包含功能的实现
2. C#接口成员的访问级别是默认的(默认为public),不可以使用
其他修饰词修饰
3. C#接口成员不能有static,abstract,override,virtual修饰
4. 接口一旦被实现,就必须实现接口当中的所有成员,除非实现类
本身是抽象类
2. C#接口成员的访问级别是默认的(默认为public),不可以使用
其他修饰词修饰
3. C#接口成员不能有static,abstract,override,virtual修饰
4. 接口一旦被实现,就必须实现接口当中的所有成员,除非实现类
本身是抽象类
4. 接口无法直接进行实例化,因为其成员必须通过由实现接口的任何类或
结构来实现
5. 接口可以包含事件,索引器,方法和属性,但是不能包含字段。
6. 类的继承只能单继承,接口的实现支持多实现
结构来实现
5. 接口可以包含事件,索引器,方法和属性,但是不能包含字段。
6. 类的继承只能单继承,接口的实现支持多实现
接口的使用
接口的定义:接口的声明使用interface关键字
格式:访问修饰符 interface 接口名{ 接口成员 }
格式:访问修饰符 interface 接口名{ 接口成员 }
注意⚠:接口中方法的定义不允许加上访问修饰符,默认修饰符为public。
接口的实现:在实现接口的类或结构后使用冒号加上要实现的接口名。
实现多个接口时,多个接口之间使用逗号隔开。
接口的实现:在实现接口的类或结构后使用冒号加上要实现的接口名。
实现多个接口时,多个接口之间使用逗号隔开。
注意⚠:类实现接口就必须实现接口当中定义的所有方法,除非该
类是抽象类。
类是抽象类。
接口与抽象类
接口与抽象类非常相似,它定义了一些未实现的属性和方法。所有继承
它的类都继承这些成员,在这个角度上,可以把接口理解为一个类的模
板。接口最终的目的是起到统一的作用。
它的类都继承这些成员,在这个角度上,可以把接口理解为一个类的模
板。接口最终的目的是起到统一的作用。
相同点:
1. 两者都不能被实例化
2. 两者都包含了由其他类或结构继承或实现的抽象成员
2. 两者都包含了由其他类或结构继承或实现的抽象成员
不同点:
1. 抽象类当中除了拥有抽象成员外还可以拥有非抽象成员;而接口中所有
的所有成员都是抽象的
2. 抽象成员可以使用修饰符修饰,接口当中接口成员访问级别是默认不可
修改的,并且默认是public
3. 接口当中不可以包含构造方法,析构方法,静态成员以及常量
4. C#类只支持单继承,接口支持多支持
的所有成员都是抽象的
2. 抽象成员可以使用修饰符修饰,接口当中接口成员访问级别是默认不可
修改的,并且默认是public
3. 接口当中不可以包含构造方法,析构方法,静态成员以及常量
4. C#类只支持单继承,接口支持多支持
--------------------------------------------------------------------------------------------------------------------
主函数
using System;
namespace Lesson11_1
{
class MainClass
{
public static void Main (string[] args)
{
Soldier s = new Soldier ();
while (true) {
char c = Console.ReadKey ().KeyChar;
if (c == 'W' || c == 'w') {
s.Move ();
}else if (c == ' ') {
s.Jump ();
}else if (c == 'j') {
s.SitDown();
}else if (c == 'k') {
s.Sleep();
}
}
}
}
//定义接口---接口不能被实例化
public interface IFly
{
// string name;//接口不可以有字段
//接口中的方法不能有访问修饰符,不能有具体的实现
string Name {
get;
set;
}
void Fly();
}
public interface ISleep
{
void Sleep();
}
public class Bird:IFly,ISleep{
public string Name {
get;
set;
}
public void Sleep ()
{
}
//继承子接口类必须实现接口的方法
public void Fly ()
{
}
}
// public abstract class AbsClass:IFly{
// public void Fly ()
// {
//
// }
// }
public interface IEat:IFly{
}
public struct MyStruct:IFly
{
public void Fly ()
{
}
public string Name {
get;
set;
}
}
}
namespace Lesson11_1
{
class MainClass
{
public static void Main (string[] args)
{
Soldier s = new Soldier ();
while (true) {
char c = Console.ReadKey ().KeyChar;
if (c == 'W' || c == 'w') {
s.Move ();
}else if (c == ' ') {
s.Jump ();
}else if (c == 'j') {
s.SitDown();
}else if (c == 'k') {
s.Sleep();
}
}
}
}
//定义接口---接口不能被实例化
public interface IFly
{
// string name;//接口不可以有字段
//接口中的方法不能有访问修饰符,不能有具体的实现
string Name {
get;
set;
}
void Fly();
}
public interface ISleep
{
void Sleep();
}
public class Bird:IFly,ISleep{
public string Name {
get;
set;
}
public void Sleep ()
{
}
//继承子接口类必须实现接口的方法
public void Fly ()
{
}
}
// public abstract class AbsClass:IFly{
// public void Fly ()
// {
//
// }
// }
public interface IEat:IFly{
}
public struct MyStruct:IFly
{
public void Fly ()
{
}
public string Name {
get;
set;
}
}
}
------------------------------------------------------------------------------------------------------------------------
泛 型
什么是泛型
我们在编写程序时经常遇到两个模块的功能非常相似,只是因为参数类
型不同,所以分别写多个方法处理每种数据类型,因为方法的参数类型
不同没法重用同样功能的代码
型不同,所以分别写多个方法处理每种数据类型,因为方法的参数类型
不同没法重用同样功能的代码
C#中的泛型能够将类型作为参数来传递,即在创建类型时用一个特定
的符号如“T”来作为一个占位符,代替实际的类型,等待在实例化时
再用一个实际的类型来代替
的符号如“T”来作为一个占位符,代替实际的类型,等待在实例化时
再用一个实际的类型来代替
泛型的优点
1. 使用泛型可以的重用代码,保护类型的安全以及提高性能
2. 降低强制转换或装箱操作的成本和风险
3. 可以对泛型参数进行限定以访问特定数据类型的方法
2. 降低强制转换或装箱操作的成本和风险
3. 可以对泛型参数进行限定以访问特定数据类型的方法
泛型类型参数注意点
1. 泛型类型参数可以有多个
2. 泛型类型参数可以是编译器识别的任何数据类型
3. 泛型类型参数命名需要遵守命名规则
(1) 使用描述性名称命名泛型类型,并且使用T作为前缀
(2) 单个字母名称完全可以让人了解其表示的含义使用单个大写字母命名
2. 泛型类型参数可以是编译器识别的任何数据类型
3. 泛型类型参数命名需要遵守命名规则
(1) 使用描述性名称命名泛型类型,并且使用T作为前缀
(2) 单个字母名称完全可以让人了解其表示的含义使用单个大写字母命名
泛型类型参数的约束
在定义泛型类时,可以对客户端代码能够在实例化类时用于类型参
数的类型种类施加限制。 如果客户端代码尝试使用某个约束所不允
许的类型来实例化类,则会产生编译时错误。 这些限制称为约束。
where关键字:
在C#中对泛型类型参数的约束使用where上下文关键字。
数的类型种类施加限制。 如果客户端代码尝试使用某个约束所不允
许的类型来实例化类,则会产生编译时错误。 这些限制称为约束。
where关键字:
在C#中对泛型类型参数的约束使用where上下文关键字。
泛型类型参数常用的约束类型
1. where T:struct :表示泛型T是值类型(小数,整数,char,bool,
struct)
2. where T:class :表示泛型T是引用类型
3. where T:new() :表示这个泛型具有一个无参数的构造方法,如果有
多个约束,new()必须放在最后
4. where T:基类名 :表示这个泛型是该基类或者其派生类
5. where T:接口名 :表示泛型是实现了该接口的类型
struct)
2. where T:class :表示泛型T是引用类型
3. where T:new() :表示这个泛型具有一个无参数的构造方法,如果有
多个约束,new()必须放在最后
4. where T:基类名 :表示这个泛型是该基类或者其派生类
5. where T:接口名 :表示泛型是实现了该接口的类型
使用约束的好处
通过约束类型参数,可以增加约束类型及其继承层次结构中的所有类
型所支持的允许操作和方法调用的数量
型所支持的允许操作和方法调用的数量
注意⚠:
可以对多个参数应用约束,也可以对同一参数进行多个约束。
可以对多个参数应用约束,也可以对同一参数进行多个约束。
未绑定的类型参数
1. 未绑定的类型参数是指那些没有约束的类型参数
2. 不能使用!= 和 == 运算符,因为无法保证具体类型参数能支持这些
运算符
3. 可以在它们与 System.Object 之间来回转换,或将它们显式转换为
任何接口类型
4. 可以将它们与 null 进行比较。 将未绑定的参数与 null 进行比较时,
如果类型参数为值类型,则该比较将始终返回 false。
2. 不能使用!= 和 == 运算符,因为无法保证具体类型参数能支持这些
运算符
3. 可以在它们与 System.Object 之间来回转换,或将它们显式转换为
任何接口类型
4. 可以将它们与 null 进行比较。 将未绑定的参数与 null 进行比较时,
如果类型参数为值类型,则该比较将始终返回 false。
泛型方法
泛型方法是使用泛型类型参数声明的方法,当方法中存在某些参数的
类型不明确的时候就可以使用泛型方法。未知具体类型的参数就使用
泛型类型参数替代
格式: 访问修饰符 返回值类型 方法名<泛型类型参数>(参数列表){
方法体。
}
类型不明确的时候就可以使用泛型方法。未知具体类型的参数就使用
泛型类型参数替代
格式: 访问修饰符 返回值类型 方法名<泛型类型参数>(参数列表){
方法体。
}
重载:泛型方法支持使用多种泛型类型参数进行重载。
泛型类
泛型类封装了不是特定于具体数据类型的操作,当类中存在未知参数
类型的时候就可以使用泛型类
格式:
修饰符 class 类名<泛型类型参数>{
类成员
}
类型的时候就可以使用泛型类
格式:
修饰符 class 类名<泛型类型参数>{
类成员
}
泛型类设计规则
1. 将哪些类型通用化为泛型类型参数
2. 如果存在约束,应对泛型类型参数应用什么约束
3. 是否将泛型行为分解为基类和子类
4. 是否实现一个或多个泛型接口
2. 如果存在约束,应对泛型类型参数应用什么约束
3. 是否将泛型行为分解为基类和子类
4. 是否实现一个或多个泛型接口
--------------------------------------------------------------------------------------------------------------------------
Practice类
using System;
using System.Text;
namespace Lesson11_2
{
public class Practice<T> where T:IComparable
{
public T[] array;
public Practice()
{
array = new T[10];
}
public void Sort(){
for (int i = 0; i < 10 - 1; i++) {
for (int j = 0; j < 10 - i - 1; j++) {
int res = array [j].CompareTo (array [j+1]);
if (res > 0) {
T t = array [j];
array [j] = array [j + 1];
array [j + 1] = t;
}
}
}
}
}
public class Practice1<T> where T:IComparable
{
public string s;
private T[] t;
private int count;
public int Capacity{
get{
return t.Length;
}
}
public Practice1()
{
t = new T[count];
}
public StringBuilder Connect(){
//string str;
StringBuilder s = new StringBuilder();
for (int i = 0; i < Capacity; i++) {
s.Append (t [i].ToString ());
}
return s;
}
}
}
----------------------------------------------------------------------------------------------------------------------
using System.Text;
namespace Lesson11_2
{
public class Practice<T> where T:IComparable
{
public T[] array;
public Practice()
{
array = new T[10];
}
public void Sort(){
for (int i = 0; i < 10 - 1; i++) {
for (int j = 0; j < 10 - i - 1; j++) {
int res = array [j].CompareTo (array [j+1]);
if (res > 0) {
T t = array [j];
array [j] = array [j + 1];
array [j + 1] = t;
}
}
}
}
}
public class Practice1<T> where T:IComparable
{
public string s;
private T[] t;
private int count;
public int Capacity{
get{
return t.Length;
}
}
public Practice1()
{
t = new T[count];
}
public StringBuilder Connect(){
//string str;
StringBuilder s = new StringBuilder();
for (int i = 0; i < Capacity; i++) {
s.Append (t [i].ToString ());
}
return s;
}
}
}
----------------------------------------------------------------------------------------------------------------------
MyList类
using System;
namespace Lesson11_2
{
//struct可以将泛型限定值类型中
//new()限定TT类必须有无参数的构造函数
public class MyList<T,TT> where T:struct where TT:new()
{
T[] array;
int count;
public MyList ()
{
array = new T[count];
}
// public T[] Return<T>(params T[] a){
// return a;
// }
public T[] Array{
get{
return array;
}
}
public void Test<TT>(TT a) where TT:class{
}
}
public class Clacc{
public string name;
public Clacc(){
}
public Clacc(string name)
{
this.name = name;
}
}
}
namespace Lesson11_2
{
//struct可以将泛型限定值类型中
//new()限定TT类必须有无参数的构造函数
public class MyList<T,TT> where T:struct where TT:new()
{
T[] array;
int count;
public MyList ()
{
array = new T[count];
}
// public T[] Return<T>(params T[] a){
// return a;
// }
public T[] Array{
get{
return array;
}
}
public void Test<TT>(TT a) where TT:class{
}
}
public class Clacc{
public string name;
public Clacc(){
}
public Clacc(string name)
{
this.name = name;
}
}
}
----------------------------------------------------------------------------------------------------------------------
Mymath类
using System;
namespace Lesson11_2
{
public class Mymath<T> where T:Animal
{
public Mymath ()
{
}
//计算两个数值的和
// public float Add(float a,float b){
// return a + b;
// }
// int a = 3;
// object b = a;//装箱操作
// int c = (int)b;//拆箱操作
//装箱和拆箱系统有额外的开销(降低性能)
//使用object来接收任意类型的参数,存在 装箱和拆箱的操作
// public object Add(object a,object b){
// return a + b;
// }
//方法列表中,参数的类型不确定
public void Swap(T obj1,T obj2){
string temp = obj1.name;
obj1.name = obj2.name;
obj2.name = temp;
}
}
public class Animal{
public string name;
}
public class Person:Animal{
public Person(string name){
this.name = name;
}
}
}
namespace Lesson11_2
{
public class Mymath<T> where T:Animal
{
public Mymath ()
{
}
//计算两个数值的和
// public float Add(float a,float b){
// return a + b;
// }
// int a = 3;
// object b = a;//装箱操作
// int c = (int)b;//拆箱操作
//装箱和拆箱系统有额外的开销(降低性能)
//使用object来接收任意类型的参数,存在 装箱和拆箱的操作
// public object Add(object a,object b){
// return a + b;
// }
//方法列表中,参数的类型不确定
public void Swap(T obj1,T obj2){
string temp = obj1.name;
obj1.name = obj2.name;
obj2.name = temp;
}
}
public class Animal{
public string name;
}
public class Person:Animal{
public Person(string name){
this.name = name;
}
}
}
----------------------------------------------------------------------------------------------------------------------
主函数
using System;
namespace Lesson11_2
{
class MainClass
{
public static void Main (string[] args)
{
// Mymath<Person> m = new Mymath<Person> ();
// Person p1 = new Person ("狗蛋");
// Person p2 = new Person ("铁柱");
// m.Swap (p1, p2);
// Console.WriteLine (p1.name);
// Console.WriteLine (p2.name);
// MyList m = new MyList ();
// int[] a = m.Return<int> (1, 2, 3, 4, 5, 6);
// MyList<int,Clacc> m = new MyList<int,Clacc>();
// m.Test (new Clacc ("XX"));
}
}
}
namespace Lesson11_2
{
class MainClass
{
public static void Main (string[] args)
{
// Mymath<Person> m = new Mymath<Person> ();
// Person p1 = new Person ("狗蛋");
// Person p2 = new Person ("铁柱");
// m.Swap (p1, p2);
// Console.WriteLine (p1.name);
// Console.WriteLine (p2.name);
// MyList m = new MyList ();
// int[] a = m.Return<int> (1, 2, 3, 4, 5, 6);
// MyList<int,Clacc> m = new MyList<int,Clacc>();
// m.Test (new Clacc ("XX"));
}
}
}