0

我与另一位程序员同事就接口的范围发生了争执。

假设我们有以下内容:

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 处理掉。然而,由于接口在设计上是一个抽象契约,其成员必须由使用它的对象实现,所以只要使用接口,接口就不会失去其实现。它不像是创建一个“接口”类型的另一个对象。接口只是指向实现者的那些抽象成员的指针。

你们能帮我解决这个纠纷吗?

谢谢,

<bleepzter />
4

4 回答 4

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());
于 2011-01-27T21:23:02.433 回答
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
}
于 2011-01-27T21:16:38.557 回答
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;
}
于 2011-01-27T21:18:38.600 回答
0

听起来你是对的,但我觉得我们错过了讨论的一部分,因为我们不知道你在创建(和转换)对象后对它做了什么。

在您的示例中:

    SomeFoo fooClassInstance = new SomeFoo("test");

此时,您对 fooClassInstance 所引用的 SomeFoo 对象有了一个引用。

    IFoo fooInterface = (IFoo)fooClassInstance;

此时,您有两个对 SomeFoo 对象的引用(由 fooClassInstance 和 fooInterface 引用)。

所以是的,取决于你如何使用它, fooClassInstance 可能会超出范围。但是仍然有对它的引用(fooInterface),所以它不会被垃圾收集。此外,fooInterface 引用可以转换回 SomeFoo。

于 2011-01-27T21:23:11.330 回答