IList和List根本区别
IList<T>
List<T>
IList<T> list=new List<T>();
知道IList是接口,List是一个实现IList的类,List可以隐式转换为IList
但是感觉这样还没有真正理解他们的区别,心里面还有疑问:
1、List实现了IList的哪些方法?是实体类T里面的字段?
2、IList既然是个接口,它为什么可以充当数据源?
3、IList<T> list=new List<T>();这样转化的用意是什么?
------解决方案--------------------1不知道怎么回答你,
2/3可以一并回答,IList<T> list=new List<T>();得到的是 List<T>的实体,所以可以做数据源,这样写的用意就是初始化成实现类List<T>的一个实体,貌似没什么其他特别的
------解决方案--------------------这些问题和 IList 或者 List 无关,表明lz的基础知识不扎实,对接口和泛型的理解不到位。
这三个问题本身问的都不对
1、List实现了IList的哪些方法?是实体类T里面的字段?
List还是IList泛型和T无关,T也不是实体类。
难道你没有见过 List<int> 或者 List<string> 么?
2、IList既然是个接口,它为什么可以充当数据源?
IList没有办法充当数据源,而是实现了 IList 接口的类的实例对象充当数据源。
3、IList<T> list=new List<T>();这样转化的用意是什么?
这里没有任何转化。
------解决方案--------------------C#高级编程第6版第108页,找到“把引用变量声明为接口引用的方式,这表示它可以指向实现这个接口的任何类的实例。但我们只能通过这些引用调用接口的方法--如果要调用由类执行的、不在接口中的方法,就需要把引用强制转换为合适的类型。接口引用完全可以看做是类引用--但接口引用的强大之处在于,它可以引用任何实现该接口的类。”
------解决方案--------------------至于说给变量赋值,那其实很简单,不要想太复杂了。比如说
A a=b;
这就是把b变量引用的对象同时也让变量a来引用。编译器回去检查b变量声明时的类型是否兼容于A,例如A是其父类、其具有的接口。假设你这样声明了,那么编译器也就放过它了。
比如说我写
string b = "asdf";
int a = b;
这显然会被编译器挑出来bug。这是因为编译器知道int跟string不兼容。
同样地,编译器知道你的赋值表达式右边的变量是 List<T>类型,左边的变量是IList<T>类型,于是编译就通过了,就允许左边的变量也去引用右边的变量所引用的对象了。
------解决方案--------------------所谓的“List<T>可以隐式转换为IList<T>”,其实运行时什么都不用做,就是正常地去让左边的变量引用右边的变量所引用的对象就行了。这里不要纠结“转换”这个词。这只是变量声明上面有差别,而两个变量所引用的对象没有差别,具体对象其实没有做任何转换。
一个对象可以有很多的“侧面”,就好象张柏芝是一个人,也是一个女人,也是一个母亲,也是一个离婚女人,也是一个名人,也是一个演员,等等。她有很多个侧面,其中“女人”也就是一个“人”,一个“母亲”或者一个“离婚女人”也就是一个“女人”,一个演员也就是一个人,等等,因此我可以只说很具体的类型而不说抽象的类型,我说她是一个名人的时候你肯定知道她也是一个人而不是一个动物。
把List<T>的对象引用赋值给IList<T>的变量也是这样,它们是兼容的。就好象我说一个是名人,你就知道他也是人,而反之则不一定成立。
程序允许你以多个变量、以多态的方式来引用对象。这是很基本的编程概念。同时编译器要尽可能多地检查出来类型不兼容的bug,让bug出现在编译时期,而不是在运行时才崩溃。
对于使用一个IList<T>对象作为数据源的宿主程序来说,它使用传递给他的对象的这个“侧面”上的功能来操作。就好象某人跟张柏芝交往时只是使用其作为女人的这个侧面,而不关心她作为演员这个侧面。这就是面向接口编程,就是去目标对象上去找它为了这个接口而定义的功能方法的入口,而不关心它其它的接口定义(在List<T>上有而在IList<T>上没有的那些)的功能入口。