web-dev-qa-db-ja.com

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

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

200
i3ensays

「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"を使用する必要がある唯一の場所は、メソッドが基本クラスバージョンにまったく関連していない場合です。

178
albertein

私はいつも写真でこのようなことをより簡単に理解しています:

繰り返しますが、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型の変数に格納していることです(これはキャストに似ています)

クラスを宣言するときにvirtual/overrideを使用したかnewを使用したかに応じて、結果は次のようになります。

Virtual/Override explanation image

223
Orion Edwards

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

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;
    }
}
41
Franci Penov

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になります。

19
Joseph Daigle

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

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

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

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

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

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

(new SubClass()).NewBar()

SubClassのNewBar()メソッドを呼び出します。

9
Wedge

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

8
tvanfosson

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

詳細については、以下のリンクをご覧ください...

[〜#〜] msdn [〜#〜] および その他

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

説明の私のバージョンは、違いを理解するためにpropertiesを使用することから来ています。

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には2GetSomethingプロパティがあります。実際には、FooBarの2つのバージョンのプロパティがあり、どちらを使用するかを知るためです。 、c#は現在の型のプロパティを「選択」します。

バーのバージョンを使用する場合は、オーバーライドまたはFoo foo代わりに。

Bar barには1のみがあり、完全に必要ですnewGetSomethingの動作。

1
droritos

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

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

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

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

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

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

0
Emre Tapcı