C# - キーワードの使用法 virtual+override と新しい
-
03-07-2019 - |
質問
基本型でメソッドを宣言することとの違いは何ですか?virtual
" そして、それを子型で使用してオーバーライドします。"override
" キーワードを単に使用するのではなく、"new
子型でマッチングメソッドを宣言するときに「キーワード?」
解決
" 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から取得した基本コード)
したがって、実際のポリモーフィズムを行っている場合は、常にオーバーライドする必要があります。 " new"を使用する必要がある唯一の場所メソッドが基本クラスのバージョンに一切関連していない場合です。
他のヒント
私はいつも写真でこのようなことをより簡単に理解できます:
もう一度、joseph daigleのコードを取得します
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
の変数に格納しています> strong>(これはキャストに似ています)
クラスを宣言するときに 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
キーワードは、実際にはその特定のタイプにのみ存在する完全に新しいメンバーを作成します。
たとえば
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( )
は Foo
ではなく Bar
に移動します。
virtual / override は、2つのメソッドが関連しており、状況によっては最初の(仮想)メソッドを呼び出していると思われる場合に、2番目の(オーバーライドされた)メソッドを呼び出すことが実際に正しいことをコンパイラーに伝えます代わりにメソッド。これがポリモーフィズムの基礎です。
(new SubClass() as BaseClass).VirtualFoo()
サブクラスのオーバーライドされたVirtualFoo()メソッドを呼び出します。
new は、基本クラスのメソッドと同じ名前の派生クラスにメソッドを追加することをコンパイラーに伝えますが、それらは相互に関係がありません。
(new SubClass() as BaseClass).NewBar()
BaseClassのNewBar()メソッドを呼び出しますが、
(new SubClass()).NewBar()
SubClassのNewBar()メソッドを呼び出します。
技術的な詳細だけでなく、仮想/オーバーライドを使用すると、設計に関する多くのセマンティック情報が伝達されると思います。メソッドvirtualを宣言すると、実装クラスが独自のデフォルト以外の実装を提供することを期待していることを示します。同様に、基本クラスでこれを省略すると、すべての実装クラスでデフォルトのメソッドで十分であるという期待が宣言されます。同様に、抽象宣言を使用して、クラスの実装に独自の実装を強制することができます。繰り返しになりますが、これはプログラマーがコードがどのように使用されることを期待するかについて多くのことを伝えていると思います。基本クラスと実装クラスの両方を書いていて、新しいクラスを使用していることに気付いた場合は、親でメソッドを仮想化せず、具体的に意図を宣言するという決定を真剣に考え直します。
-
new
キーワードは非表示用です。 -実行時にメソッドを非表示にしていることを意味します。出力はベースクラスメソッドに基づきます。
オーバーライド用の -
override
。 -は、基本クラスの参照を使用して派生クラスメソッドを呼び出すことを意味します。出力は、派生クラスメソッドに基づきます。
説明の私のバージョンは、プロパティを使用して違いを理解するのに役立ちます。
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
を使用し、どちらを使用するかを知るために、c#" picks"現在のタイプのプロパティ。
バーのバージョンを使用する場合は、オーバーライドを使用するか、代わりに Foo foo
を使用します。
GetSomething
の完全に新しい動作が必要なため、 バーバー
には 1 しかありません。
メソッドに何もマークしないことは、次のことを意味します。ランタイム型 (静的バインディング) ではなく、オブジェクトのコンパイル型を使用してこのメソッドをバインドします。
メソッドをマークする virtual
手段:コンパイル時タイプ (動的バインディング) ではなく、オブジェクトの実行時タイプを使用してこのメソッドをバインドします。
基本クラスのマーク付け virtual
を使用したメソッド override
派生クラスでは次のことを意味します。これは、オブジェクトのランタイム型 (動的バインディング) を使用してバインドされるメソッドです。
基本クラスのマーク付け virtual
を使用したメソッド new
派生クラスでは次のことを意味します。これは新しいメソッドであり、基本クラス内の同じ名前のメソッドとは関係がなく、オブジェクトのコンパイル時の型 (静的バインディング) を使用してバインドされる必要があります。
基本クラスをマークしない virtual
派生クラスのメソッドは次のことを意味します。このメソッドは次のようにマークされています new
(静的バインディング)。
メソッドのマーク付け abstract
手段:このメソッドは仮想メソッドですが、本体は宣言しません。また、そのクラスも抽象 (動的バインディング) です。