接口定义了所有类继承接口时应遵循的语法合同。接口定义了语法合同 “是什么” 部分,派生类定义了语法合同 “怎么做” 部分。
接口定义了属性、方法和事件,这些都是接口的成员。接口只包含了成员的声明。成员的定义是派生类的责任。接口提供了派生类应遵循的标准结构。
接口使得实现接口的类或结构在形式上保持一致。
抽象类在某种程度上与接口类似,但是,它们大多只是用在当只有少数方法由基类声明由派生类实现时。
1、 实现接口的任何类或结构必须实现其所有成员的方法。
2、接口不能直接实例化,但是可以通过指向子类间接实例化。
3、 接口可以包含方法和属性的声明,但不能包含字段。
4、接口中所有方法、属性默认为public,不能在后面再添加修饰符。
5、类或结构可以实现多个接口。 类可以继承基类并实现一个或多个接口。
借鉴:链接: https://www.cnblogs.com/zhangzheny/archive/2007/12/24/1012790.html.
1.类是对对象的抽象,可以把抽象类理解为把类当作对象,抽象成的类叫做抽象类.而接口只是一个行为的规范或规定,微软的自定义接口总是后带able字段,证明其是表述一类类“我能做。。。”.抽象类更多的是定义在一系列紧密相关的类间,而接口大多数是关系疏松但都实现某一功能的类中.
2.接口基本上不具备继承的任何具体特点,它仅仅承诺了能够调用的方法;
3.一个类一次可以实现若干个接口,但是只能扩展一个父类
4.接口可以用于支持回调,而继承并不具备这个特点.
5.抽象类不能被密封。
6.抽象类实现的具体方法默认为虚的,但实现接口的类中的接口方法却默认为非虚的,当然您也可以声明为虚的.
7.(接口)与非抽象类类似,抽象类也必须为在该类的基类列表中列出的接口的所有成员提供它自己的实现。但是,允许抽象类将接口方法映射到抽象方法上。
8.抽象类实现了oop中的一个原则,把可变的与不可变的分离。抽象类和接口就是定义为不可变的,而把可变的座位子类去实现。
9.好的接口定义应该是具有专一功能性的,而不是多功能的,否则造成接口污染。如果一个类只是实现了这个接口的中一个功能,而不得不去实现接口中的其他方法,就叫接口污染。
10.尽量避免使用继承来实现组建功能,而是使用黑箱复用,即对象组合。因为继承的层次增多,造成最直接的后果就是当你调用这个类群中某一类,就必须把他们全部加载到栈中!后果可想而知.(结合堆栈原理理解)。同时,有心的朋友可以留意到微软在构建一个类时,很多时候用到了对象组合的方法。比如asp.net中,Page类,有Server Request等属性,但其实他们都是某个类的对象。使用Page类的这个对象来调用另外的类的方法和属性,这个是非常基本的一个设计原则。
11.如果抽象类实现接口,则可以把接口中方法映射到抽象类中作为抽象方法而不必实现,而在抽象类的子类中实现接口中方法.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
//接口 泛型
namespace lesson11
{
//定义一个接口
interface USB
{
//接口中所有方法、属性默认为public,不能在后面再添加 修饰符。
void Read();
//接口可以包含方法和属性的声明,但不能包含字段。例如 string name = "";
int Name { set; get; }
}
interface U
{
void Wirte();
}
//C#只支持单继承,即子类只能继承一个父类,而一个子类却能够实现多个接口。
class KeyCode:USB,U
{
public void Read()
{
Console.WriteLine("加载中请稍后");
}
public void Wirte()
{
Console.WriteLine("抓紧写下来");
}
public int Name { set; get;}
}
class Key :USB
{
public void Read()
{
Console.WriteLine("加载成功");
}
public int Name { set; get; }
}
class Program
{
static void Main(string[] args)
{
//接口不能直接实例化,但是可以通过指向子类间接实例化。
USB _u = (USB)new KeyCode();
_u.Read();
U _us = (U)new KeyCode();
_us.Wirte();
USB _w = (USB)new Key();
_w.Read();
}
}
}
我们在编写程序时,经常遇到两个模块的功能非常相似,只是一个是处理int数据,另一个是处string数据,或者其他自定义的数据类型,但我们没有办法,只能分别写多个方法处理每个数据类型,因为方法的参数类型不同。例如:
class Program
{
public static void Swp(int a ,int b)
{
Console.WriteLine(a + b );
}
public static void Swp(string a ,string b )
{
Console.WriteLine(a + b);
}
static void Main(string[] args)
{
Swp(1,2);
Swp("1\t","11");
}
}
可能会想到用object,来解决这个问题。但是,缺陷的:
1.会出现装箱、折箱操作,这将在托管堆上分配和回收大量的变量,若数据量大,则性能损失非常严重。
2.在处理引用类型时,虽然没有装箱和折箱操作,但将用到数据类型的强制转换操作,增加处理器的负担。
public static void Swp(object a , object b)
{
Console.WriteLine(a.ToString() + b.ToString() );
}
static void Main(string[] args)
{
Swp(1,3);
}
C#中的泛型能够将类型作为参数来传递,即在创建类型时用一个特定的符号,如“T”来作为一个占位
符,代替实际的类型,等待在实例化时用一个实际的类型来代替。
public class People<T>
{
public void Sum(T a,T b)
{
T _temp = a;
a = b;
b = _temp;
}
}
class Program
{
static void Main(string[] args)
{
People<int> _people = new People<int>();
_people.Sum(20,30);
}
}
泛型的约束:
用来指定该泛型是值类型还是引用类型。
约束类型:
// An highlighted block
var foo = 'bar';
一、使用泛型类型可以最大限度地重用代码、保护类型的
安全以及提高性能。
二、降低了强制转换或装箱操作的成本或风险。
三、可以对泛型类进行约束以访问特定数据类型的方法。
泛型成员因类型不确定,可能是类、结构体、字符、枚举…… 所以不能使用算术运算符、比较运算符等进行运算。(+ - * /等) 注意,可以使用赋值运算符。
使用泛型是一种增强程序功能的技术,具体表现在以下几个方面:
1、它有助于您最大限度地重用代码、保护类型的安全以及提高性能。
2、可以创建泛型集合类。.NET 框架类库在 System.Collections.Generic 命名空间中包含了一些新的泛型集合类。可以使用这些泛型集合类来替代 System.Collections 中的集合类。
3、可以创建自己的泛型接口、泛型类、泛型方法、泛型事件和泛型委托。
4、可以对泛型类进行约束以访问特定数据类型的方法。
5、关于泛型数据类型中使用的类型的信息可在运行时通过使用反射获取。
泛型类封装不是特定于具体数据类型的操作。 泛型类最常用于集合。 像从集合中添加和移除项这样的操作都以大体上相同的方式执行,与所存储数据的类型无关。
sing System;
using System.Collections.Generic;
namespace GenericMethodAppl
{
class Program
{
static void Swap<T>(ref T lhs, ref T rhs)
{
T temp;
temp = lhs;
lhs = rhs;
rhs = temp;
}
static void Main(string[] args)
{
int a, b;
char c, d;
a = 10;
b = 20;
c = 'I';
d = 'V';
// 在交换之前显示值
Console.WriteLine("Int values before calling swap:");
Console.WriteLine("a = {0}, b = {1}", a, b);
Console.WriteLine("Char values before calling swap:");
Console.WriteLine("c = {0}, d = {1}", c, d);
// 调用 swap
Swap<int>(ref a, ref b);
Swap<char>(ref c, ref d);
// 在交换之后显示值
Console.WriteLine("Int values after calling swap:");
Console.WriteLine("a = {0}, b = {1}", a, b);
Console.WriteLine("Char values after calling swap:");
Console.WriteLine("c = {0}, d = {1}", c, d);
Console.ReadKey();
}
}
}
using System;
using System.Collections.Generic;
delegate T NumberChanger<T>(T n);
namespace GenericDelegateAppl
{
class TestDelegate
{
static int num = 10;
public static int AddNum(int p)
{
num += p;
return num;
}
public static int MultNum(int q)
{
num *= q;
return num;
}
public static int getNum()
{
return num;
}
static void Main(string[] args)
{
// 创建委托实例
NumberChanger<int> nc1 = new NumberChanger<int>(AddNum);
NumberChanger<int> nc2 = new NumberChanger<int>(MultNum);
// 使用委托对象调用方法
nc1(25);
Console.WriteLine("Value of Num: {0}", getNum());
nc2(5);
Console.WriteLine("Value of Num: {0}", getNum());
Console.ReadKey();
}
}
}
泛型占位符:
<泛型占位符>
可以写多个占位符,需要用 逗号 隔开。
通常用一个大写的英文字母表示(可以写成小写,也可以用多个英文字母,特殊符号不能用
泛型的使用: