C#でのシャドウイングとオーバーライドの違いは何ですか?


100

C#でのメソッドのシャドウオーバーライドの違いは何ですか?

回答:


152

相続...

次のクラスがあるとします。

class A {
   public int Foo(){ return 5;}
   public virtual int Bar(){return 5;}
}
class B : A{
   public new int Foo() { return 1;}     //shadow
   public override int Bar() {return 1;} //override
}

次に、これを呼び出すと:

A clA = new A();
B clB = new B();

Console.WriteLine(clA.Foo()); // output 5
Console.WriteLine(clA.Bar()); // output 5
Console.WriteLine(clB.Foo()); // output 1
Console.WriteLine(clB.Bar()); // output 1

//now let's cast B to an A class
Console.WriteLine(((A)clB).Foo()); // output 5 <<<-- shadow
Console.WriteLine(((A)clB).Bar()); // output 1

基本クラスがあり、継承されたクラスの代わりにすべてのコードで基本クラスを使用し、シャドウを使用すると、オブジェクトの実際の型の継承ツリーをたどるのではなく、基本クラスが返す値が返されます。

ここでコードを実行

私が理解していることを願っています:)


16
オーバーライドはポリモーフィズムを提供し、シャドウイングは階層のそのレベルで異なる実装を提供しますが、ポリモーフィックではありません。
デビッドロドリゲス-ドリベス2008

@dribeas、その結論を引き出すためにどのような多態性の定義を使用しますか?
AnthonyWJones 2008

9
@AnthonyWJones、ポリモーフィズムは、1つの(派生)型を別の(ベース)型として使用する機能であり、実際の実装(動作)は実際の特定の(派生)型の実装です。あなたがオーバーライドする場合は、導出方法は、ベースを参照することにより呼び出されますが、あなたがシャドウ場合には当てはまりません
デビッド・ロドリゲス- dribeasは

2
私には、サンプルコードにエラーがあるようです。キャストは((A)clB).Foo()である必要がありますか?
Trendl 2009年

1
いいえ、バーは仮想なので、Bバーと呼ばれます
Stormenet 2010

32

シャドウイングは、実際にはC#で非表示と呼ばれるもののVB用語です。

多くの場合、Stormenetによる回答のように、非表示(VBでのシャドウイング)とオーバーライドが表示されます。

仮想メソッドはサブクラスによってオーバーライドされることが示され、スーパークラスタイプまたはスーパークラスの内部コードからでもそのメソッドを呼び出すと、サブクラスから置換実装が呼び出されます。

次にnew、サブクラスで同じシグネチャを持つメソッドを定義するときに、キーワードを使用して非表示になっている具象メソッド(仮想または抽象としてマークされていないメソッド)が表示されます。この場合、メソッドがスーパークラスタイプで呼び出されると、元の実装が使用され、新しい実装はサブクラスでのみ使用できます。

ただし、見落とされることが多いのは、仮想メソッドを非表示にすることもできるということです。

class A
{
    public virtual void DoStuff() { // original implementation }
}

class B : A
{
    public new void DoStuff() {  //new implementation }
}

B b = new B();
A a = b;

b.DoStuff(); //calls new implementation
a.DoStuff(); //calls original implementation.

上記の例では、DoStuffが具象になり、オーバーライドできないことに注意してください。ただし、virtualおよびnewキーワードの両方を一緒に使用することもできます。

class A
{
    public virtual void DoStuff() { // original implementation }
}

class B : A
{
    public new virtual void DoStuff() {  //new implementation }
}

class C : B
{
    public override void DoStuff() { //replacement implementation }
}

C c = new C();
B b = c;
A a = b;

c.DoStuff(); //calls replacement implementation
b.DoStuff(); //calls replacement implementation
a.DoStuff(); //calls original implementation.

関連するすべてのメソッドが仮想であってもnew、B での使用はAの実装を非表示にするため、CのオーバーライドはAの仮想メソッドには影響しません。

編集:この回答に対するコメントで、上記は危険であるか、少なくとも特に有用ではない可能性があることが指摘されています。私はそう言うのは危険である可能性があり、もしそれが少しでも役に立つならそこに出て行くでしょう。

特に、アクセシビリティ修飾子も変更すると、さまざまな問題が発生する可能性があります。例えば:-

public class Foo
{
    internal Foo() { }
    protected virtual string Thing() { return "foo"; }
}

public class Bar : Foo
{
 internal new string Thing() { return "bar"; }
}

外部相続にBarFooシング()のの実装では、づけし及びオーバーライド残ります。.NETタイプのルールに従ってすべての合法で説明可能なことは、決して直感的ではありません。

この回答を掲載して、自由に使用できる手法の提案ではなく、物事の仕組みについての理解を深めました。


2
それを知ってうれしい。ただし、その使用は危険な場合があります:)
Stormenet 2008

2
すべてのツールは、適切に使用しないと危険な場合があります。
AnthonyWJones 2008

1
しかし、それは使いやすさは本当に疑わしいようです!これを使用した「深刻な」オープンソースアプリはありますか?
Jox、

4
使いやすさ?有用性を意味しますか?フリンジにあるものは、必要になるまでは役に立たないように見えるかもしれません。
AnthonyWJones 2008

シャドーイングが登場するのは、仮想プレイと新規プレイの場合のみです。@Stormenetは、仮想のものでない限り、独自のメソッドを呼び出すのはクラスの通常の動作であるため、オーバーライドのみを説明しています。
Sumit Kapadia 2013


5

シャドウイングはVB.NETの概念です。C#では、シャドウイングは非表示として知られています。派生クラスメソッドを非表示にします。'new'キーワードを使用して実行されます。

Overrideキーワードは、派生クラスで基本クラスメソッド(「仮想」とマークされている)の完全に新しい実装を提供するために使用されます。


もしかして。代わりに、派生クラスメソッドを非表示にし、代わりに基本クラスメソッドを使用します。?
shaijut

0

基本的に以下のようなものがあれば、

Class A
{
}

Class B:A
{
}

A a = new B();

オブジェクト 'a'で呼び出すメソッドはすべて 'a'のタイプで作成されます(ここでタイプは 'A'です)。ただし、クラスAにすでに存在するクラスBに同じメソッドを実装すると、コンパイラーは「新しい」キーワードを使用するよう警告します。「新規」を使用すると、警告が消えます。これ以外は、継承されたクラスで「新規」を使用するか使用しないかの違いはありません。

状況によっては、オブジェクトタイプのメソッドを呼び出す代わりに、特定のインスタンスがその時点で保持している参照クラスのメソッドを呼び出す必要がある場合があります。上記の場合、それが保持する参照は「B」ですが、タイプは「A」です。したがって、メソッド呼び出しを「B」で行う必要がある場合は、Virtualとオーバーライドを使用してこれを実現します。

お役に立てれば...

ダニエル・サンディープ。


0

クラスの内容を変更できない場合があるとしましょう。たとえばA、いくつかのメソッドを使用したいが、共通の名前を持つメソッドがある場合は、newキーワードによって独自のメソッド実装を使用できます。

重要なポイントは、参照とオブジェクトの両方が同じタイプでなければならないということです。

class A
{
    public void Test()
    {
        Console.WriteLine("base");
    }
}

class B : A
{
    public new void Test()
    {
        Console.WriteLine("sub");
    }

    public static void Main(string[] args)
    {
        A a = new A();
        B aa = new B();
        a.Test();
        aa.Test();
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.