我知道我們無法創建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