virtual
子型で一致するメソッドを宣言するときoverride
に単に " new
"キーワードを使用するのではなく、基本型 " "でメソッドを宣言してから、 " "キーワードを使用して子型でオーバーライドすることの違いは何ですか?
virtual
子型で一致するメソッドを宣言するときoverride
に単に " new
"キーワードを使用するのではなく、基本型 " "でメソッドを宣言してから、 " "キーワードを使用して子型でオーバーライドすることの違いは何ですか?
回答:
「新しい」キーワードはオーバーライドしません。基本クラスのメソッドとは何の関係もない新しいメソッドを意味します。
public class Foo
{
public bool DoSomething() { return false; }
}
public class Bar : Foo
{
public new bool DoSomething() { return true; }
}
public class Test
{
public static void Main ()
{
Foo test = new Bar ();
Console.WriteLine (test.DoSomething ());
}
}
これはfalseを出力します。オーバーライドを使用した場合、trueが出力されます。
(Joseph Daigleから取得した基本コード)
したがって、実際のポリモーフィズムを実行している場合は、常にオーバーライドする必要があります。「新規」を使用する必要がある唯一の場所は、メソッドが基本クラスのバージョンにまったく関連していない場合です。
virtual
ベースにしてoverride
得られましたで?なぜそれが存在するのですか?コードは引き続きw / oでも実行new
されます。つまり、単なる読みやすさですか?
私は常にこのようなものを写真でより簡単に理解できると思います:
もう一度、ジョセフデイグルのコードを取り上げます。
public class Foo
{
public /*virtual*/ bool DoSomething() { return false; }
}
public class Bar : Foo
{
public /*override or new*/ bool DoSomething() { return true; }
}
次に、次のようなコードを呼び出します。
Foo a = new Bar();
a.DoSomething();
注:重要なことは、オブジェクトは実際にはであるということですがBar
、それを型の変数に格納していますFoo
(これはキャストに似ています)。
あなたが使用するかどうかに応じて、以下のようにその後の結果は次のようになりますvirtual
/ override
またはnew
あなたのクラスを宣言するとき。
以下は、仮想メソッドと非仮想メソッドの動作の違いを理解するためのコードです。
class A
{
public void foo()
{
Console.WriteLine("A::foo()");
}
public virtual void bar()
{
Console.WriteLine("A::bar()");
}
}
class B : A
{
public new void foo()
{
Console.WriteLine("B::foo()");
}
public override void bar()
{
Console.WriteLine("B::bar()");
}
}
class Program
{
static int Main(string[] args)
{
B b = new B();
A a = b;
a.foo(); // Prints A::foo
b.foo(); // Prints B::foo
a.bar(); // Prints B::bar
b.bar(); // Prints B::bar
return 0;
}
}
new
オーバーライドを使用しないだけで同じように見えるのに、なぜ基本メソッドを「隠す」のに使用するのですか?
virtual
、コンパイラーは、クラス「virtual
new
キーワードは、実際にはその特定のタイプに存在する完全に新しいメンバーを作成します。
例えば
public class Foo
{
public bool DoSomething() { return false; }
}
public class Bar : Foo
{
public new bool DoSomething() { return true; }
}
メソッドは両方のタイプに存在します。リフレクションを使用して型のメンバーを取得Bar
すると、実際にはDoSomething()
まったく同じに見える2つのメソッドが呼び出されます。を使用new
することにより、基本クラスの実装を効果的に非表示にして、クラスがBar
(この例では)から派生したときに、へのメソッド呼び出しがにbase.DoSomething()
行くのBar
ではなくに行くようにしFoo
ます。
virtual / overrideは、2つのメソッドが関連していること、および最初の(仮想)メソッドを呼び出すと思われる状況では、代わりに2番目の(オーバーライドされた)メソッドを呼び出すことが実際に正しいことをコンパイラーに伝えます。これがポリモーフィズムの基礎です。
(new SubClass() as BaseClass).VirtualFoo()
サブクラスのオーバーライドされたVirtualFoo()メソッドを呼び出します。
newは、基本クラスのメソッドと同じ名前の派生クラスにメソッドを追加していることをコンパイラに通知しますが、それらは互いに関係がありません。
(new SubClass() as BaseClass).NewBar()
BaseClassのNewBar()メソッドを呼び出しますが、
(new SubClass()).NewBar()
サブクラスのNewBar()メソッドを呼び出します。
技術的な詳細だけでなく、仮想/オーバーライドを使用すると、設計に関する多くのセマンティック情報が伝達されると思います。メソッドを仮想として宣言すると、実装するクラスが独自のデフォルト以外の実装を提供する可能性があることを期待していることを示します。同様に、基本クラスでこれを省略すると、すべての実装クラスでデフォルトのメソッドで十分であるはずであるとの期待が宣言されます。同様に、抽象宣言を使用して、実装クラスに独自の実装を提供させることができます。繰り返しますが、これはプログラマーがコードが使用されることを期待する方法について多くのことを伝えていると思います。基本クラスと実装クラスの両方を作成していて、newを使用していることに気付いた場合は、メソッドを親で仮想化しないという決定を真剣に考え直し、具体的に私の意図を宣言します。
私のバージョンの説明は、違いを理解するのに役立つプロパティを使用することから来ています。
override
簡単ですよね?基になるタイプは、親のタイプをオーバーライドします。
new
おそらく誤解を招く可能性があります(私にとってはそうでした)。プロパティを使用すると、理解しやすくなります。
public class Foo
{
public bool GetSomething => false;
}
public class Bar : Foo
{
public new bool GetSomething => true;
}
public static void Main(string[] args)
{
Foo foo = new Bar();
Console.WriteLine(foo.GetSomething);
Bar bar = new Bar();
Console.WriteLine(bar.GetSomething);
}
あなたはそれが気づくことができ、デバッガを使用しFoo foo
ている2つの GetSomething
、それは実際に財産の2つのバージョンが、持っているとして、プロパティをFoo
のとBar
のを、と知っているの使用への1つ、C#の『ピック』現在の型のプロパティ。
バーのバージョンを使用したい場合は、Foo foo
代わりにオーバーライドまたはを使用します。
Bar bar
にはまったく新しい動作が必要なため、には1しかありません。GetSomething
メソッドに何かをマークしないことは、実行時のタイプ(静的バインディング)ではなく、オブジェクトのコンパイルタイプを使用してこのメソッドをバインドすることを意味します。
メソッドをvirtual
手段でマークする:このメソッドは、コンパイル時のタイプ(動的バインディング)ではなく、オブジェクトのランタイムタイプを使用してバインドします。
派生クラスで基本クラスvirtual
メソッドをマークするoverride
ことは、オブジェクトのランタイムタイプを使用してバインドされるメソッド(動的バインディング)であることを意味します。
派生クラスで基本クラスvirtual
メソッドをマークするnew
ことは、これは新しいメソッドであり、基本クラスの同じ名前のメソッドとは関係がないため、オブジェクトのコンパイル時の型(静的バインド)を使用してバインドする必要があります。
virtual
派生クラスで基本クラスメソッドをマークしないことは、このメソッドがnew
(静的バインディング)としてマークされることを意味します。
メソッドのマーク abstract
をは、このメソッドは仮想ですが、本体を宣言せず、そのクラスも抽象的(動的バインディング)で意味します。
new
すると、同じ名前の新しいメンバーが作成され、元のメンバーが非表示になりoverride
、継承されたメンバーの実装が拡張されます」