2011-01-27 43 views
0

我與另外一位程序員在接口範圍上發生爭執。什麼是基本的C#接口範圍?

假設我們有以下幾點:

public interface IFoo 
{ 
    string Bar { get; set; } 
} 

public class SomeFoo: IFoo 
{ 
    public string Bar { get; set; } 

    public SomeFoo(string bar) 
    { 
     this.Bar = bar; 
    } 
} 

public class Consumer 
{ 
    public void DoSomething() 
    { 
     SomeFoo fooClassInstance = new SomeFoo("test"); 
     IFoo fooInterface = (IFoo)fooClassInstance; 

     // do something with fooInterface. 
    } 
} 

所以現在的問題是:1。 是否有可能在fooClassInstance走出去的範圍別的東西釋放fooInterface實例之前?

有人認爲對象(fooClassInstance)可能超出範圍。

我相信它不能。當GC確定物體不在範圍內時,物體可能會或可能不會被GC處置。然而,由於接口在設計上是一個抽象契約,其成員必須由使用它的對象來實現,而接口只要使用該接口就不會失去它的實現。它不像整個另一個對象是由「interface」類型創建的。接口只是一個指向實現者的抽象成員的指針。

你們能幫我解決這個爭議嗎?

感謝,

<bleepzter /> 
+0

一個接口沒有實現,所以,是的,*實現*接口*的類可以*並且將超出範圍。一個接口就像一個合同 - 沒有任何實現只是你將實現什麼的承諾,因此沒有垃圾收集。在你的例子中,你創建了一個對原始對象的引用並將其轉換爲一個接口 - 這是COM中舊的IUnknown :: QueryInterface(雖然現在有很多不同 - 同樣的概念)。 – SRM 2011-01-27 21:18:44

+1

在您的示例中,類和接口實例將同時超出作用域。 – Victor 2011-01-27 21:22:35

+1

不需要將`fooClassInstance`強制轉換爲`IFoo`。它已經*是*`IFoo`。 – 2011-01-27 21:23:29

回答

1

呃,你是什麼意思「失去執行力」?這是沒有意義的。一個類型實現了一個接口,它不能「實現」一個接口。

就你的代碼示例而言,分配的對象的生命週期結束時,它不再有任何根(也就是說,GC不再可以訪問)。對它的引用是對它的引用,而不管引用的類型如何(即如果引用類型是某種派生類型或父類型,則無關緊要)。

ISomething Sample() { 
    Something s1 = new Something(); 
    s2.DoSomething(); // Assuming s is the only reference to s, then it no longer is 
         // rooted after this expression 

    Something s2 = new Something(); 
    ISomething is1 = s2; 
    s2 = null; 
    is1.DoSomething(); // The reference remains valid and the lifetime of the 
         // object created continues until we release all 
         // remaining references to it. 
    return is1; 
} 
2

我認爲你是得過且過實例的引用之間的界線。 fooClassInstance即使對象的實例仍然存在(因爲fooInterface仍然包含對它的引用),可以將超出範圍(即不能再引用它)。

例如,如果您執行以下操作,fooClassInstance在花括號之後將不可用,但fooInterface將會。

public void DoSomething() 
{ 
    IFoo fooInterface; 
    { 
     SomeFoo fooClassInstance = new SomeFoo("test"); 
     fooInterface = (IFoo)fooClassInstance; 
    } 

    // do something with fooInterface, but NOT with fooClassInstance 
} 
3

雖然肯定是有在條款有些混亂您正在使用(我會讓別人解決這個問題),我想明白你在說什麼,你是基本上是正確的。

特別是,它聽起來像你的同事認爲,這種情況正在發生:

// Now there is this "SomeFoo" object somewhere in memory. 
SomeFoo fooClassInstance = new SomeFoo("test"); 

// Now there is this "IFoo" object somewhere in memory. 
IFoo fooInterface = (IFoo)fooClassInstance; 

// Let's say down the road somewhere, fooClassInstance is set to null or a different 
// object. Your coworker believes that the object it originally pointed to will then 
// have no references to it and will thus be eligible for garbage collection? 

如果上面是你的同事的想法準確地表述,那麼你的同事是錯誤的,你是對的。 fooInterface變量包含對fooClassInstance有參考的同一對象的引用。您可以輕鬆簡單地通過執行以下操作進行驗證:

SomeFoo fooClassInstance = new SomeFoo("test"); 
IFoo fooInterface = (IFoo)fooClassInstance; 
bool sameObject = ReferenceEquals(fooClassInstance, fooInterface); 

如果ReferenceEquals回報true,那麼這兩個變量引用內存中的同一個對象。


如果你的同事需要進一步說服,試圖顯示他/她是這樣的:

List<int> list = new List<int> { 1, 2, 3 }; 

// This cast is actually not needed; I'm just including it so that it mirrors 
// your example code. 
IList<int> ilist = (IList<int>)list; 

// Now we remove an item from the List<int> object referenced by list. 
list.Remove(3); 

// Is it in ilist? No--they are the same List<int> object. 
Console.WriteLine(ilist.Contains(3)); 

// How about we remove an item using ilist, now? 
ilist.Remove(2); 

// Is it in list? Nope--same object. 
Console.WriteLine(list.Contains(2)); 

// And here's one last thing to note: the type of a VARIABLE is not the same 
// as the type of the OBJECT it references. ilist may be typed as IList<int>, 
// but it points to an object that is truly a List<int>. 
Console.WriteLine(ilist.GetType()); 
0

聽起來像你是正確的,但我覺得我們缺少的一部分因爲我們不知道在創建(和施放)對象後你在做什麼。

在您的例子:

SomeFoo fooClassInstance = new SomeFoo("test"); 

在這一點上,你有一個參考的fooClassInstance引用的SomeFoo對象。

IFoo fooInterface = (IFoo)fooClassInstance; 

在這一點上,你有兩個引用到SomeFoo對象(雙方fooClassInstance和fooInterface參考)。

所以是的,取決於你如何使用它,fooClassInstance可能超出範圍。但是它仍然有一個參考(fooInterface),所以它不會被垃圾收集。另外,fooInterface引用可以轉換回SomeFoo。