Какова основная область применения интерфейса 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 решает, что объект (ы) больше не находится в области видимости. Однако, поскольку интерфейсы являются абстрактным контрактом, члены которого должны быть реализованы объектом, который его использует, интерфейс не может потерять свою реализацию, пока используется интерфейс. Это не совсем другой объект, созданный по типу "интерфейс". Интерфейс является просто указателем на эти абстрактные члены разработчика.

Ребята, можете ли вы помочь мне разрешить этот спор?

Спасибо,

<bleepzter />

4 ответа

Решение

Что ты имеешь в виду под "потерять свою реализацию"? Это бессмысленно. Тип реализует интерфейс, он не может "реализовать" интерфейс.

Что касается вашего примера кода, время жизни выделенного объекта заканчивается в тот момент, когда у него больше нет корней (иначе, он больше не доступен для 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;
}

Хотя в используемых вами терминах определенно есть некоторая путаница (я позволю кому-то другому заняться этим вопросом), я думаю, я понимаю, что вы говорите, и вы в основном правы.

В частности, ваш коллега считает, что это происходит:

// 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());

Я думаю, что вы путаете грань между экземпляром и ссылкой. 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
}

Похоже, вы правы, но я чувствую, что мы упускаем часть обсуждения, так как мы не знаем, что вы делаете с объектом после того, как вы его создали (и произвели).

В вашем примере:

    SomeFoo fooClassInstance = new SomeFoo("test");

На данный момент у вас есть одна ссылка на объект SomeFoo, на который ссылается fooClassInstance.

    IFoo fooInterface = (IFoo)fooClassInstance;

На данный момент у вас есть две ссылки на объект SomeFoo (на которые ссылаются как fooClassInstance, так и fooInterface).

Так что да, в зависимости от того, как вы его используете, fooClassInstance может выйти из области видимости. Но есть ссылка на него (fooInterface), поэтому он не будет собирать мусор. Кроме того, ссылка на fooInterface может быть возвращена к SomeFoo.

Другие вопросы по тегам