C#-キーワードの使用法virtual + overrideとnew


204

virtual子型で一致するメソッドを宣言するときoverrideに単に " new"キーワードを使用するのではなく、基本型 " "でメソッドを宣言してから、 " "キーワードを使用して子型でオーバーライドすることの違いは何ですか?


3
MSDNによると、「使用newすると、同じ名前の新しいメンバーが作成され、元のメンバーが非表示になりoverride、継承されたメンバーの実装が拡張されます」
AminM


回答:


181

「新しい」キーワードはオーバーライドしません。基本クラスのメソッドとは何の関係もない新しいメソッドを意味します。

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から取得した基本コード)

したがって、実際のポリモーフィズムを実行している場合は、常にオーバーライドする必要があります。「新規」を使用する必要がある唯一の場所は、メソッドが基本クラスのバージョンにまったく関連していない場合です。


コードを修正する必要があります。私はメソッドを静的にしました(これは「新しい」キーワードの使用に有効です)。しかし、インスタンスメソッドを使用する方が明確であると判断しました。
ジョセフデイグル

1
ありがとう、私は「静的な」部分を逃しました。未来にもっと注意を払うべきです
albertein

1
ここではFoo test = new Bar()という行が重要であることに注意してください。メトッドのnew / overrideキーワードは、BarをFoo変数に入れたときに呼び出されるメトッドを決定します。
トーマスN

...それは単にとまったく同じだしませ持つvirtualベースにしてoverride得られましたで?なぜそれが存在するのですか?コードは引き続きw / oでも実行newされます。つまり、単なる読みやすさですか?
Don Cheadle 2015年

正直なところ、あなたの答えは曖昧です。newとvirtual-overrideはまったく同じことを行います。唯一の違いは、newが親クラスのメソッドを非表示にし、オーバーライドすることです。まあ、オーバーライドします。もちろん、テストオブジェクトのタイプがFooであるためfalseを出力し、タイプBarの場合はtrueを出力します。ただし、かなりトリッキーな例です。
MrSilent

228

私は常にこのようなものを写真でより簡単に理解できると思います:

もう一度、ジョセフデイグルのコードを取り上げます。

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あなたのクラスを宣言するとき。

仮想/オーバーライドの説明画像


3
ありがとう....しかし、あなたが言ったキャスティングに関して上の画像について少し説明していただけませんか?
odiseh 2009

おっと、これらの数行を私の前の行に追加するのを忘れた場合。コメント:仮想/オーバーライドおよび非仮想/新規は多態性の概念にのみ使用されていることを意味し、単に変数を宣言するとき(キャストを使用しない)は意味がないのですか?再度、感謝します。
odiseh 2009

この答えはまさに私が探していたものです。私が持っていた唯一の問題は、私は自分の携帯電話を経由してアクセスしなければならなかったので、画像は私の職場でブロックされているflickrのです...
mezoid

7
質問に答えるための真の努力。
iMatoria 2011

画像を修正できるかどうか賛成しますか?企業ファイアウォールの背後でブロックされています...
Jeremy Thompson

43

以下は、仮想メソッドと非仮想メソッドの動作の違いを理解するためのコードです。

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オーバーライドを使用しないだけで同じように見えるのに、なぜ基本メソッドを「隠す」のに使用するのですか?
Don Cheadle

1
基本クラスがオーバーライドされるのを防ぐために作成されたとは思いません。名前の衝突を回避するために作成されたと思います。そうでないメソッドはオーバーライドできずvirtual、コンパイラーは、クラス「virtual
bloodline

19

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ます。


9

virtual / overrideは、2つのメソッドが関連していること、および最初の(仮想)メソッドを呼び出すと思われる状況では、代わりに2番目の(オーバーライドされた)メソッドを呼び出すことが実際に正しいことをコンパイラーに伝えます。これがポリモーフィズムの基礎です。

(new SubClass() as BaseClass).VirtualFoo()

サブクラスのオーバーライドされたVirtualFoo()メソッドを呼び出します。

newは、基本クラスのメソッドと同じ名前の派生クラスにメソッドを追加していることをコンパイラに通知しますが、それらは互いに関係がありません。

(new SubClass() as BaseClass).NewBar()

BaseClassのNewBar()メソッドを呼び出しますが、

(new SubClass()).NewBar()

サブクラスのNewBar()メソッドを呼び出します。


本当にこの文のように「コンパイラに伝えます」
ミナガブリエル

「ポリモーフィズムの基礎」は別の格好いい格言です:)
Jeremy Thompson

8

技術的な詳細だけでなく、仮想/オーバーライドを使用すると、設計に関する多くのセマンティック情報が伝達されると思います。メソッドを仮想として宣言すると、実装するクラスが独自のデフォルト以外の実装を提供する可能性があることを期待していることを示します。同様に、基本クラスでこれを省略すると、すべての実装クラスでデフォルトのメソッドで十分であるはずであるとの期待が宣言されます。同様に、抽象宣言を使用して、実装クラスに独自の実装を提供させることができます。繰り返しますが、これはプログラマーがコードが使用されることを期待する方法について多くのことを伝えていると思います。基本クラスと実装クラスの両方を作成していて、newを使用していることに気付いた場合は、メソッドを親で仮想化しないという決定を真剣に考え直し、具体的に私の意図を宣言します。


新しいvsオーバーライドの技術的な説明は確かですが、この回答は、使用する開発者をガイドするのに最も役立つようです。
サリー

4

overrideキーワードとnewキーワードの違いは、前者はメソッドのオーバーライドを行い、後者はメソッドの非表示を行うことです。

詳細については、次のリンクを確認してください...

MSDN および その他


3
  • newキーワードは非表示です。-実行時にメソッドを非表示にすることを意味します。出力は、ベースクラスメソッドに基づきます。
  • overrideオーバーライドするため。-基本クラスの参照を使用して派生クラスメソッドを呼び出すことを意味します。出力は派生クラスメソッドに基づきます。

1

私のバージョンの説明は、違いを理解するのに役立つプロパティを使用することから来ています

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


0

メソッドに何かをマークしないことは、実行時のタイプ(静的バインディング)ではなく、オブジェクトのコンパイルタイプを使用してこのメ​​ソッドをバインドすることを意味します。

メソッドをvirtual手段でマークする:このメソッドは、コンパイル時のタイプ(動的バインディング)ではなく、オブジェクトのランタイムタイプを使用してバインドします。

派生クラスで基本クラスvirtualメソッドをマークするoverrideことは、オブジェクトのランタイムタイプを使用してバインドされるメソッド(動的バインディング)であることを意味します。

派生クラスで基本クラスvirtualメソッドをマークするnewことは、これは新しいメソッドであり、基本クラスの同じ名前のメソッドとは関係がないため、オブジェクトのコンパイル時の型(静的バインド)を使用してバインドする必要があります。

virtual派生クラスで基本クラスメソッドをマークしないことは、このメソッドがnew(静的バインディング)としてマークされることを意味します。

メソッドのマーク abstractをは、このメソッドは仮想ですが、本体を宣言せず、そのクラスも抽象的(動的バインディング)で意味します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.