メソッドシグネチャの新しいキーワード


113

リファクタリングの実行中に、次の例のようなメソッドを作成してしまいました。単純化のためにデータ型が変更されました。

私は以前に次のような割り当てステートメントを持っていました:

MyObject myVar = new MyObject();

これは偶然にこれにリファクタリングされました:

private static new MyObject CreateSomething()
{
  return new MyObject{"Something New"};
}

これは私の側での切り取り/貼り付けエラーの結果でしたが、newキーワードin private static newは有効でコンパイルされます。

質問newキーワードはメソッドシグネチャで何を意味しますか?C#3.0で導入されたものだと思いますか?

これはどう違いますoverrideか?


5
メソッドを非表示にすることの望ましさに関するいくつかのメモ:blogs.msdn.com/ericlippert/archive/2008/05/21/…–
Eric Lippert

2
@Eric ..素晴らしい投稿。そのようにメソッドを非表示にすることは考えていませんでした。そうですが、オブジェクトは1つのものですが、現在は別のものとして提示しているので、ASとして提示しているものの動作が必要です。賢い...
BFree 09年

1
将来の重複する質問と私はある程度詳しく答えてみました:c#で新しいキーワードを使用する
Ken Kin

1
newメソッド(または他の型メンバー)の修飾子としての使用は、「C#3.0で導入されたもの」ではありません。C#の最初のバージョンからずっと存在しています。
Jeppe Stig Nielsen

1
SOには、この質問の重複が4つあるようです。私の意見では、これはあなたに最良の理解を与えるでしょう:stackoverflow.com/questions/3117838/…。@EricLippertが回答します。
Raikol Amaro

回答:


101

MSDNからの新しいキーワードリファレンス:

MSDNリファレンス

これは、Microsoft MVPからネット上で見つけた例で、意味のあるものです 。Linkto Original

public class A
{
   public virtual void One();
   public void Two();
}

public class B : A
{
   public override void One();
   public new void Two();
}

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

a.One(); // Calls implementation in B
a.Two(); // Calls implementation in A
b.One(); // Calls implementation in B
b.Two(); // Calls implementation in B

オーバーライドは、非常に特殊な場合にのみ使用できます。MSDNから:

非仮想メソッドまたは静的メソッドをオーバーライドすることはできません。オーバーライドされる基本メソッドは、仮想、抽象、またはオーバーライドでなければなりません。

したがって、非仮想メソッドおよび静的メソッドを「オーバーライド」できるようにするには、「new」キーワードが必要です。


4
私はサンプルを実行するだけです。 "new"を指定しなくてもオーバーライドされますよね?
Michael Sync

2
@MichaelSync正確に、なぜ新しいキーワードに言及する必要があるのですか?
ZoomIn 2013

2
「新しい修飾子を使用せずにメンバーを非表示にすることはできますが、コンパイラの警告が表示されます。」リンクされたドキュメントごと。したがって、このキーワードによって、非表示にする意図が明確になり、警告は発行されません。
ジム

1
-1->まったく必要ありません-動作は同じです。初心者にnewは非常に混乱していますが、文字通り読みやすくするためだけにあると思います-コンパイラは、ベースと同じ名前の派生クラスメソッドを呼び出すと、基本クラスのメソッドを取得できないことを警告しています考えてみてください...それは奇妙なことです...
Don Cheadle

1
完全を期すために、AクラスとBクラスの両方がインターフェースをIMyInterface実装する場合、Derivedクラスの実装が呼び出されます。したがってIMyInterface c = new B()、Bクラスの実装を呼び出します。1つのクラスだけがインターフェースを実装する場合、それを実装するクラスのメソッドが呼び出されます。
Nullius

61

いいえ、それは実際には「新しい」ものではありません(しゃれを許してください)。これは基本的に、メソッドを「隠す」ために使用されます。IE:

public class Base
{
   public virtual void Method(){}
}

public class Derived : Base
{
   public new void Method(){}
}

次にこれを行うと:

Base b = new Derived();
b.Method();

Baseのメソッドは、派生されるメソッドではなく、呼び出されるメソッドです。

その他の情報:http : //www.akadia.com/services/dotnet_polymorphism.html

あなたの編集について:私が与えた例では、「new」を使用する代わりに「override」する場合は、b.Method();を呼び出します。派生クラスのメソッドは、ポリモーフィズムのために呼び出されます。


public class Base {public virtual void Method(){Console.WriteLine( "Base"); }} public class Derived:Base {public void Method(){Console.WriteLine( "Derived"); }}ベースb = new Derived(); b.Method(); 私は、「ベース」..私は派生クラスで「新しい」を追加した場合、私はまだ取得「ベース」..ました
マイケル・シンク

@michaelメソッドはまだ仮想です
ルーンFS

@MichaelSync:そのコードで警告が表示されるはずです。警告Derived.Method() 'は、継承されたメンバー' Base.Method() 'を非表示にします。現在のメンバーがその実装をオーバーライドするには、overrideキーワードを追加します。それ以外の場合は、新しいキーワードを追加します。
Christopher McAtackney、2011

2
@MichaelSync「オーバーライド」という単語が省略された場合、デフォルトの動作は「新規」、たとえばメソッドの非表示になります。したがって、あなたが新しい単語を残しているという事実は違いがありません。
BFree

1
はい。私もそう思います。C#は、「新しい」キーワードを追加していないことを確認なぜ...それは...単なる警告を作るためには姿を消したのですstackoverflow.com/questions/8502661/...
マイケル・シンク

22

他の人が説明したように、既存のメソッドを隠すために使用されます。親クラスで仮想ではないメソッドをオーバーライドするのに役立ちます。

「新しい」メンバーの作成は多態的ではないことに注意してください。オブジェクトを基本型にキャストした場合、派生型のメンバーは使用されません。

基本クラスがある場合:

public class BaseClass
{
    public void DoSomething() { }
}

そして派生クラス:

public class DerivedType : BaseClass
{
    public new void DoSomething() {}

}

の型を宣言してDerivedTypeからキャストすると、メソッドDoSomething()はポリモーフィックではなく、派生クラスではなく基本クラスのメソッドを呼び出します。

BaseClass t = new DerivedType();
t.DoSomething();// Calls the "DoSomething()" method of the base class.

1
それは...だけでなくも、あなたがDerievedTypeから「新しい」を削除し、基本クラスからメソッドを呼び出します
マイケル・シンク

2
私はあなたの2番目の段落がこのトピック全体を釘付けにしていると思います。基本クラス参照からの呼び出しを処理する場合、「新規」はポリモーフィックではありません...すなわち。あなたは正確に何を得るあなたは、あなたが電話をかける際に指定します。「オーバーライド」は多態的です...つまり。クラス階層が指定するものを取得します。
Jonathon Reinhart

これは漠然と定義されていますか?初心者には非常にイライラします。そして、いいえ、それはポリモーフィズムとは何の関係もありません-それは単にoverrideメソッドシグネチャに含まれていないのとまったく同じ動作をします
Don Cheadle

何から何が隠されているのか?new派生型から基本型を隠すことはできません。常に、base.<type>表記法を使用して基本型にアクセスできないからです。
thatWiseGuy 2017

@thatWiseGuyコードで派生クラスを使用するときに基本メソッドが呼び出されないという意味で「非表示」です。それでもbase.<method>、を使用して内部的に呼び出すことができ、コードで基本型にキャストした場合は外部から呼び出すこともできます。基本的なメソッドを「非表示にする」よりも、「オーバーライドする」と考える方が技術的に正確です。
ダンハーバート

7

ドキュメントから:

派生クラスのメソッドの前に新しいキーワードがある場合、メソッドは基本クラスのメソッドから独立していると定義されます。

これが実際に意味すること:

別のクラスから継承し、同じシグニチャーを共有するメソッドがある場合は、それを「新規」として定義して、親クラスから独立させることができます。つまり、「親」クラスへの参照がある場合はその実装が実行され、子クラスへの参照がある場合はその実装が実行されます。

個人的には、「新しい」キーワードを避けようとします。これは、通常、クラス階層が間違っていることを意味しますが、役立つ場合があります。1つの場所は、バージョン管理と下位互換性のためです。

これについては、MSDNに多くの情報があります。


この動作が発生するという事実は、newそこにいることとは何の関係もありません。構文/読みやすさです。
Don Cheadle

3

これは、メソッドがメソッドを基本クラスによって継承された同じ名前で置き換えることを意味します。あなたの場合、基本クラスにその名前のメソッドがない可能性があります。つまり、新しいキーワードはまったく不要です。


3

要するに、必須ではありません。動作は変更されません。読みやすくするために完全にそこにあります。

そのため、VSでは少し波線が表示されますが、コードは正しくコンパイルされ、期待どおりに実行されます。

newキーワードを作成する価値があるのは、開発者が「基本的なメソッドを隠していることを知っている、virtualまたはoverriden(多態性)に関連することを何もしていないことを知っている-自分だけのメソッドを作りたい」

それは私には少し奇妙ですが、おそらく私がJavaバックグラウンドから来ており、C#継承との間にこの根本的な違いがあるためだけかもしれませんJava:ではJava、メソッドは、で指定されない限り、デフォルトで仮想ですfinal。ではC#、メソッドは、で指定されていない限り、デフォルトでfinal / concreteですvirtual


1

MSDNから:

新しい修飾子を使用して、基本クラスから継承されたメンバーを明示的に非表示にします。継承されたメンバーを非表示にするには、同じ名前を使用して派生クラスで宣言し、新しい修飾子で変更します。


0

この落とし穴に注意してください。
基本クラスに実装されているインターフェースで定義されたメソッドがあります。次に、インターフェイスのメソッドを非表示にする派生クラスを作成しますが、派生クラスをインターフェイスの実装として具体的に宣言しないでください。その後、インターフェースへの参照を介してメソッドを呼び出すと、基本クラスのメソッドが呼び出されます。ただし、派生クラスが具体的にインターフェイスを実装している場合、そのメソッドは、使用される参照のタイプに関係なく呼び出されます。

interface IMethodToHide
{
    string MethodToHide();
}

class BaseWithMethodToHide : IMethodToHide
{
    public string MethodToHide()
    {
        return "BaseWithMethodToHide";
    }
}

class DerivedNotImplementingInterface   : BaseWithMethodToHide
{
    new public string MethodToHide()
    {
        return "DerivedNotImplementingInterface";
    }
}

class DerivedImplementingInterface : BaseWithMethodToHide, IMethodToHide
{
    new public string MethodToHide()
    {
        return "DerivedImplementingInterface";
    }
}

class Program
{
    static void Main()
    {
        var oNoI = new DerivedNotImplementingInterface();
        IMethodToHide ioNoI = new DerivedNotImplementingInterface();

        Console.WriteLine("reference to the object type DerivedNotImplementingInterface calls the method in the class " 
            + oNoI.MethodToHide());
        // calls DerivedNotImplementingInterface.MethodToHide()
        Console.WriteLine("reference to a DerivedNotImplementingInterface object via the interfce IMethodToHide calls the method in the class " 
            + ioNoI.MethodToHide());
        // calls BaseWithMethodToHide.MethodToHide()
        Console.ReadLine();

        var oI = new DerivedImplementingInterface();
        IMethodToHide ioI = new DerivedImplementingInterface();

        Console.WriteLine("reference to the object type DerivedImplementingInterface calls the method in the class " 
            + oI.MethodToHide());
        // calls DerivedImplementingInterface.MethodToHide()
        Console.WriteLine("reference to a DerivedImplementingInterface object via the interfce IMethodToHide calls the method in the class " 
            + ioI.MethodToHide());
        // calls DerivedImplementingInterface.MethodToHide()
        Console.ReadLine();

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