메서드 서명의 새 키워드


113

리팩토링을 수행하는 동안 아래 예제와 같은 메서드를 생성했습니다. 단순성을 위해 데이터 유형이 변경되었습니다.

이전에 다음과 같은 할당 문이있었습니다.

MyObject myVar = new MyObject();

이것은 우연히 리팩토링되었습니다.

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

이것은 내 부분에서 잘라 내기 / 붙여 넣기 오류의 결과 였지만 newin 키워드 private static new가 유효하고 컴파일됩니다.

질문 : new키워드는 메소드 서명에서 무엇을 의미합니까? 나는 그것이 C # 3.0에서 도입 된 것이라고 가정합니까?

이것이 어떻게 다른 override가요?


5
메소드 은닉의 타당성에 대한 몇 가지 참고 사항 : blogs.msdn.com/ericlippert/archive/2008/05/21/…
Eric Lippert

2
@Eric .. 그레이트 포스트. 나는 그런 식으로 방법을 숨기는 것을 생각한 적이 없습니다. 객체는 하나입니다.하지만 이제 우리는 그것을 다른 것으로 표현하고 있습니다. 그래서 우리는 그것을 그대로 표현하고있는 행동을 원합니다. Clever ...
BFree 2009-06-18

1
미래에 중복 된 질문이 있고 좀 더 자세히 대답 해 보았습니다. C #에서 새 키워드 사용
Ken Kin

1
사용 new방법 (또는 기타 유형의 부재)의 AA 개질제로서가 "C # 3.0 도입 무언가"가 아닙니다. C #의 첫 번째 버전 이후로 존재했습니다.
Jeppe Stig Nielsen

1
이 질문에는 4 개의 중복이 있습니다. 제 생각에 이것은 stackoverflow.com/questions/3117838/… . @EricLippert가 답변합니다.
Raikol Amaro

답변:


101

MSDN의 새로운 키워드 참조 :

MSDN 참조

다음은 인터넷에서 찾은 Microsoft MVP의 좋은 예입니다. Link to 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

2
"새 수정자를 사용하지 않고 멤버를 숨길 수 있지만 컴파일러 경고가 표시됩니다." 링크 된 문서에 따라. 따라서 키워드는 당신이 은폐하려는 의도를 분명히하고 경고가 발행되지 않습니다.
Jim Counts 2015 년

1
-1-> 전혀 필요하지 않습니다. 동작은 동일합니다. 초보자에게는 매우 혼란 스럽지만 new문자 그대로 가독성을 위해 거기에 있다고 생각합니다. 컴파일러는 단순히 기본과 같은 이름의 파생 클래스 메서드를 호출 할 때 기본 클래스의 메서드를 얻지 못할 것이라고 경고합니다. 생각하기 .... 이거 이상해 ... 순전히 가독성을 위해?
Don Cheadle

1
완전성을 위해 : A 및 B 클래스가 인터페이스 IMyInterface를 구현하는 경우 Derived 클래스의 구현이 호출됩니다. 따라서 IMyInterface c = new B()B 클래스의 구현을 호출합니다. 하나의 클래스 만 인터페이스를 구현하는 경우이를 구현하는 클래스의 메서드가 호출됩니다.
Nullius 2015

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"를 사용하는 대신 "재정의"하려면 b.Method (); Derived 클래스의 Method는 Polymorphism 때문에 호출됩니다.


공개 클래스 Base {공개 가상 void Method () {Console.WriteLine ( "Base"); }} 공개 클래스 파생 : Base {public void Method () {Console.WriteLine ( "Derived"); }}베이스 b = new Derived (); b. 방법 (); "Base"를 얻었습니다 .. Derived 클래스에 "new"를 추가해도 "Base"가 계속 나타납니다.
Michael Sync

@michael 메서드는 여전히 가상입니다
Rune FS

@MichaelSync : 해당 코드에 대한 경고가 표시되어야합니다. 경고 Derived.Method () '는 상속 된 멤버'Base.Method () '를 숨 깁니다. 현재 멤버가 해당 구현을 대체하도록하려면 override 키워드를 추가하십시오. 그렇지 않으면 새 키워드를 추가하십시오.
Christopher McAtackney 2011

2
@MichaelSync "override"라는 단어가 생략 된 경우 기본 동작은 "new"(예 : 메서드 숨김)입니다. 그래서 당신이 새로운 단어를 남기고 있다는 사실은 아무런 차이가 없습니다.
BFree

1
예. 그게 제 생각이기도합니다. C #이 "새"키워드를 추가 한 이유를 잘 모르겠습니다. 경고를 사라지게 만들기위한 것입니다 .. stackoverflow.com/questions/8502661/…
Michael Sync

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
두 번째 단락이이 전체 주제를 잘 이해하고 있다고 생각합니다. 기본 클래스 참조 에서 호출을 처리 할 때 "new"는 다형성이 아닙니다. 즉. 당신은 정확히 무엇을 얻을 당신은 당신이 전화를 걸 때 지정합니다. "override"는 다형성입니다. 클래스 계층이 지정 하는 것을 얻습니다 .
Jonathon Reinhart

이게 어떻게 그렇게 막연하게 정의 되었습니까? 초보자에게는 매우 실망 스럽습니다. 그리고 아니, 그것은 다형성과는 아무 상관이 없다 - 단순히 가지고 있지과 완전히 동일한 동작이 override메소드 서명에
돈 치들

무엇이 숨겨져 있습니까? new항상 base.<type>표기법을 사용하여 기본 유형에 액세스 할 수 없기 때문에 파생 유형에서 기본 유형 을 숨길 수는 없습니다 .
thatWiseGuy

@thatWiseGuy 코드에서 파생 클래스를 사용할 때 기본 메서드가 호출되지 않는다는 점에서 "숨겨져"있습니다. 을 사용하여 내부적으로 호출 base.<method>할 수 있으며 코드에서 기본 유형으로 캐스트하는 경우 외부 적으로 호출 할 수도 있습니다. 기본 메소드를 "숨기기"보다 "재정의"하는 것으로 생각하는 것이 기술적으로 더 정확합니다.
Dan Herbert

7

문서에서 :

파생 클래스의 메서드 앞에 new 키워드가있는 경우 메서드는 기본 클래스의 메서드와 독립적 인 것으로 정의됩니다.

이것이 실제로 의미하는 바 :

다른 클래스에서 상속하고 동일한 서명을 공유하는 메서드가있는 경우이를 'new'로 정의하여 부모 클래스와 독립적으로 만들 수 있습니다. 즉, '부모'클래스에 대한 참조가 있으면 해당 구현이 실행되고, 하위 클래스에 대한 참조가 있으면 해당 구현이 실행됩니다.

개인적으로 'new'키워드는 일반적으로 내 클래스 계층 구조가 잘못되었음을 의미하므로 피하려고하지만 유용 할 수있는 경우가 있습니다. 한 곳은 버전 관리 및 이전 버전과의 호환성입니다.

이에 대한 MSDN 에는 많은 정보가 있습니다.


이 동작이 발생한다는 사실 new은 거기에있는 것과는 아무 관련이 없습니다 . 구문 / 가독성입니다.
Don Cheadle

3

이는 메서드가 기본 클래스에서 상속 한 동일한 이름으로 메서드를 대체 함을 의미합니다. 귀하의 경우에는 기본 클래스에 해당 이름의 메서드가 없을 것입니다. 즉, 새 키워드가 완전히 불필요합니다.


3

짧게 말하면 필수 사항이 아니며 동작을 변경하지 않으며 가독성을 위해 순전히 있습니다.

그렇기 때문에 VS에서 약간 구불 구불하게 보일 수 있지만 코드는 예상대로 완벽하게 잘 컴파일되고 실행됩니다.

new개발자가 "예, 기본 메서드를 숨기고 있다는 것을 알고 있습니다. 예, virtualor overriden(다형성) 와 관련된 작업을 수행하지 않는다는 것을 알고 있습니다."라고 인정하는 경우 키워드를 만드는 것이 정말 가치가 있는지 궁금해해야합니다. 나는 정말로 그것만의 방법을 만들고 싶다. "

그것은 나에게 조금 이상한,하지만 어쩌면 단지 난에서 온 때문에 Java배경 사이의 근본적인 차이가있어 C#상속과는 Java:에서가 Java지정하지 않는 한 방법이 기본적으로 가상 있습니다 final. 에서가 C#지정하지 않는 한 방법은 기본적으로 최종 / 콘크리트입니다 virtual.


1

에서 MSDN :

new 한정자를 사용하여 기본 클래스에서 상속 된 멤버를 명시 적으로 숨 깁니다. 상속 된 멤버를 숨기려면 동일한 이름을 사용하여 파생 클래스에서 선언하고 새 수정 자로 수정합니다.


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.