我知道我们无法创建Interface
的实例。 但为什么我们可以在左侧写Interface
?那些仅仅是Interface (对于实现这个的类)的引用而不是实例?左侧的接口
如果我们不能创建接口的实例,那么这个例子中的类型是P
?
string[] names = {"John", "Bob", "Mark"};
IEnumerable<string> P = names.Where(n => n.Contains('o'));
我知道我们无法创建Interface
的实例。 但为什么我们可以在左侧写Interface
?那些仅仅是Interface (对于实现这个的类)的引用而不是实例?左侧的接口
如果我们不能创建接口的实例,那么这个例子中的类型是P
?
string[] names = {"John", "Bob", "Mark"};
IEnumerable<string> P = names.Where(n => n.Contains('o'));
P
的类型是IEnumerable<string>
在这里,您在声明局部变量P
的类型。
P
包含IEnumerable<string>
的类型,虽然您没有直接实例化接口,但可以实例化一个具体类,但只需保存对接口的引用。
由Where()
调用返回的实例需要仅遵守IEnumerable<string>
定义的合同。
确切地说,如果赋值中的左手边部分被键入为接口类型,则意味着左手边部分(变量或这样的)是对实现所述接口的类的任何实例的引用。
在本示例中,P
是对实施IEnumerable<string>
的某些内部框架类的实例的引用。由于它是一些内部类(可以隐藏在Enumerable的实现中),我们甚至无法访问类名(因此无法声明该类型的任何变量)。事实上,微软可能会改变每个.NET版本返回的实际类Where
。然而,我们也不会注意到,因为我们需要知道的是将实现IEnumerable<string>
将返回,因此我们也只是声明变量P
作为参考东西实现IEnumerable<string>
而不是而不是具体的课程。
你不能创建一个接口的实例,但你可以创建一个实现它的实例。
你在你的例子中所做的只是获取已知遵守IEnumerable<string>
定义的合同的东西(p
)。
它很容易,如果你认为它掌握的概念稍微简单来说:
IBeast mrJuggles = new Tiger();
Mr.Juggles现在是泰格 - 也是一个IBeast
。我们没有明确地创建IBeast
,我们只是指定我们创建的东西将表现为IBeast
,因此我们可以将其视为IBeast
。
我会试着从概念上解释这一点。
但为什么我们可以在左侧写Interface?
我们可以,因为这意味着:“这个对象是东西实现此接口”。
接口本身不是“某些东西” - 这就是为什么你不能直接实例化它 - 它只是一个合同。
一个接口是没用的,除非你定义了一些保证实现它所表示的合约的对象(并且公开这样或那样的方法等)。这就是你使用接口的用法。没有这个,他们就没有任何意义。
合同本身是一个抽象的概念。它需要一些东西来体现它 - 一个充满了它的物体。
看一看下面的例子:
using System.Collections.Generic;
namespace App
{
class Program
{
class Example
{
List<string> list = new List<string> { "a", "b", "c" };
public IEnumerable<string> AsEnumerable()
{
return list;
}
}
static void Main(string[] args)
{
IEnumerable<string> foo = new Example().AsEnumerable();
List<string> bar = (List<string>)foo;
}
}
}
你知道它不会崩溃?
在这一行IEnumerable<string>
:
IEnumerable<string> foo = new Example().AsEnumerable();
实际上意味着:“富是我们知道实现IEnumerable的东西”。
但它仍然是东西。它不能只有IEnumerable而只是。 IEnumerable只是我们碰巧知道的东西。
否则,我们不能将它扔回List<string>
,可以吗? (这实际上是C#中的一个常见警告,因为调用者可以执行此操作,因此可以访问Add
和Remove
方法,并与我们的列表中的内容混杂在一起,即使我们不打算这样做,这是封装泄漏)。
换句话说:IEnumerable<string>
是我们看这个物体的方式。
编辑:
由于@Kjartan建议,你可以验证这一切就像这样:
bool isFooIEnumerable = foo is IEnumerable<string>; // it's true
bool isBarIEnumerable = bar is IEnumerable<string>; // true again
bool isFooList = foo is List<string>; // yup. true
bool isBarList = bar is List<string>; // true all the way
在声明变量的类型左侧。
IEnumerable<string> stringEnumerator
你告诉从下价值stringEnumerator
这一刻可以呈现一个空引用或参考对象,它是一个字符串枚举的编译器。
所以,当你有一个像
IEnumerable<string> P = names.where(n => n.Contains('o'));
表达你说,创建一个变量p
将代表IEnumerable<string>
,并分配给它的names.where(n => n.Contains('o'));
导致“如果我们不能创建的实例接口,这个例子中P是什么类型?“我们不必知道,它是接口的*点*。它是一种实现IEnumerable的类型。精确的类型对用户无关紧要。 –
dureuill
你可能想读这个:http://stackoverflow.com/questions/6802573/c-sharp-interfaces-whats-the-point – Paddy