基本的なC#インターフェイススコープは何ですか?
-
26-10-2019 - |
質問
私は、インターフェイスの範囲について、別の仲間のプログラマーと論争をしています。
以下があるとします。
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。他の何かがFoointerfaceインスタンスをリリースする前に、FooclassInstanceが範囲外に出ることは可能ですか?
オブジェクト(FooclassInstance)が範囲外に出ることができると主張する人もいます。
私はそれができないと信じています。確かに、GCがオブジェクトがもはや範囲ではないと判断した場合、GCによってオブジェクトが廃棄される場合と廃棄されない場合があります。ただし、インターフェイスは設計によるものであるため、インターフェイスが使用される限り、インターフェイスが実装を失うことはできません。別のオブジェクトがタイプ「インターフェイス」で作成されているようなものではありません。インターフェイスは、実装者の抽象メンバーへのポインタにすぎません。
この論争の解決を手伝ってもらえますか?
ありがとう、
<bleepzter />
解決
ええと、「実装を失う」とはどういう意味ですか?それは意味がありません。タイプはインターフェイスを実装し、インターフェイスを「解明」することはできません。
コードの例が進む限り、オブジェクトの寿命は、根がなくなった瞬間に割り当てられた終わりに至るまで(別名、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
, 、次に、2つの変数がメモリ内の同じオブジェクトを参照しています。
あなたの同僚がさらに説得力を持っている必要がある場合は、彼/彼女にこのようなものを見せてみてください:
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");
この時点で、FooclassInstanceで参照されるSomeFooオブジェクトへの参照が1つあります。
IFoo fooInterface = (IFoo)fooClassInstance;
この時点で、SomeFooオブジェクト(FooclassInstanceとFoointerfaceの両方で参照)への2つの参照があります。
したがって、はい、それをどのように使用するかによって、Fooclassinstanceは範囲外に出る可能性があります。しかし、まだそれへの参照(foointerface)があるので、それはガベージを収集することはありません。また、foointerfaceリファレンスをSomefooに戻すことができます。