programing tip

새 키워드가 필요한 이유는 무엇이며 기본 동작을 숨기고 무시하지 않는 이유는 무엇입니까?

itbloger 2020. 10. 12. 07:18
반응형

새 키워드가 필요한 이유는 무엇이며 기본 동작을 숨기고 무시하지 않는 이유는 무엇입니까?


블로그 게시물 을보고 다음과 같은 질문이있었습니다.

  • new키워드 가 필요한 이유는 기본 클래스 메서드가 숨겨 지도록 지정하는 것입니다. 내 말은, 우리는 왜 그것을 필요로합니까? override키워드를 사용하지 않으면 기본 클래스 메서드를 숨기지 않습니까?
  • C #의 기본값이 숨기고 재정의하지 않는 이유는 무엇입니까? 디자이너가이 방식으로 구현 한 이유는 무엇입니까?

좋은 질문입니다. 다시 말하겠습니다.

다른 방법으로 방법을 숨기는 것이 합법적 인 이유는 무엇입니까?

예를 들어 그 질문에 답하겠습니다. CLR v1의 인터페이스가 있습니다.

interface IEnumerable
{
    IEnumerator GetEnumerator();
}

감독자. 이제 CLR에서 당신은 제네릭이 있고 V1 만 우리가 가진 거라고 제네릭 내가이 일반적인 인터페이스를 만들었을 것입니다 경우 "사람이.하지만. 내가 지금과 호환 뭔가해야하지 않았다고 생각 V2 이다 일반적인 그래서를 IEnumerable을 예상하는 코드와의 하위 호환성을 잃지 않고 제네릭의 이점을 얻습니다. "

interface IEnumerable<T> : IEnumerable
{
    IEnumerator<T> .... uh oh

무엇의 GetEnumerator 메서드를 호출 할 예정 IEnumerable<T>입니까? 당신이 기억 하고자 는 제네릭이 아닌 기본 인터페이스에서 GetEnumerator를 숨길. 당신은 결코 당신이 이전 버전과의 compat 상황에서 명시 적 아니라면 그 일이 호출되고 싶지 않습니다.

그것만으로도 방법 숨기기가 정당화됩니다. 메소드 숨김의 정당화에 대한 더 많은 생각 은 주제에 대한 내 기사를 참조하십시오 .

"new"없이 숨기면 경고가 발생하는 이유는 무엇입니까?

우리는 당신이 무언가를 숨기고 있고 우연히 그것을 할 수 있다는 것을 당신에게 알리고 싶기 때문입니다. 파생 클래스를 편집하는 대신 다른 사람이 기본 클래스를 편집하여 실수로 무언가를 숨길 수 있습니다.

왜 "새로운"없이 숨는 것은 오류가 아니라 경고입니까?

같은 이유. 새 버전의 기본 클래스를 선택했기 때문에 실수로 무언가를 숨기고있을 수 있습니다. 이것은 항상 발생합니다. FooCorp는 기본 클래스 B를 만듭니다. BarCorp는 고객이 해당 메서드를 좋아하기 때문에 Bar 메서드를 사용하여 파생 클래스 D를 만듭니다. FooCorp는 그것을보고 좋은 생각이라고 말합니다. 우리는 그 기능을 기본 클래스에 넣을 수 있습니다. 그들은 그렇게하고 Foo.DLL의 새 버전을 제공하고 BarCorp가 새 버전을 선택할 때 자신의 메서드가 이제 기본 클래스 메서드를 숨긴다는 말을 들으면 좋을 것입니다.

우리는 그 상황이 오류가 아닌 경고가 되기를 원합니다. 왜냐하면이를 오류로 만드는 것은 이것이 취약한 기본 클래스 문제의 또 다른 형태 임을 의미하기 때문 입니다. C #은 누군가가 기본 클래스를 변경할 때 파생 클래스를 사용하는 코드에 미치는 영향을 최소화하도록 신중하게 설계되었습니다.

숨기고 기본값을 재정의하지 않는 이유는 무엇입니까?

가상 재정의는 위험하기 때문 입니다. 가상 재정의를 사용하면 파생 클래스가 기본 클래스를 사용하도록 컴파일 된 코드의 동작을 변경할 수 있습니다. 당신이 뭔가해야 재정의를 만드는 같은 뭔가 위험한 일을 의식적으로 그리고 의도적으로 하지 사고에 의해를.


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

그러나 new 또는 override를 지정하지 않으면 결과 출력은 new를 지정한 것과 동일하지만 컴파일러 경고가 표시됩니다 (기본 클래스 메서드에서 메서드를 숨기고 있다는 것을 알지 못할 수도 있으므로, 또는 실제로 재정의하고 싶을 수 있으며 키워드를 포함하는 것을 잊었습니다.)

따라서 실수를 방지하고 원하는 작업을 명시 적으로 보여주고 코드를 더 읽기 쉽게 만들어 코드를 쉽게 이해할 수 있습니다.


이 컨텍스트에서 유일한 효과 new는 경고를 억제하는 것입니다. 의미 체계에는 변화가 없습니다.

따라서 한 가지 대답은 다음과 같습니다. new숨김이 의도적 이라는 것을 컴파일러에 알리고 경고를 제거해야합니다.

후속 질문은 : 메서드를 재정의 할 수 없거나 재정의 할 수없는 경우 동일한 이름의 다른 메서드를 도입하는 이유는 무엇입니까? 은폐는 본질적으로 이름 충돌이기 때문입니다. 물론 대부분의 경우 피할 것입니다.

내가 의도적으로 숨겨야한다고 생각할 수있는 유일한 이유는 인터페이스가 이름을 강요 할 때입니다.


C #에서 멤버는 기본적으로 봉인되어 있습니다. 즉, virtual또는 abstract키워드 로 표시되지 않는 한이를 재정의 할 수 없으며 이는 성능상의 이유 때문 입니다. 새로운 수정은 명시 적으로 상속 된 멤버를 숨기는 데 사용됩니다.


override키워드 를 지정하지 않고 재정의가 기본값 이면 이름이 같기 때문에 실수로 기본 메서드를 재정의 할 수 있습니다.

.Net 컴파일러 전략은 안전을 위해 무언가 잘못 될 수있는 경우 경고를 내보내는 것이므로이 경우 재정의가 기본값 인 경우 재정의 된 각 메서드에 대한 경고가 있어야합니다. 재정의 '.


내 추측은 주로 다중 인터페이스 상속 때문입니다. 신중한 인터페이스를 사용하면 두 개의 서로 다른 인터페이스가 동일한 메서드 서명을 사용할 수 있습니다. new키워드 의 사용을 허용하면 두 개의 별개의 클래스를 만드는 대신 하나의 클래스로 이러한 다른 구현을 만들 수 있습니다.

업데이트 ... Eric이이 예제를 개선하는 방법에 대한 아이디어를주었습니다.

public interface IAction1
{
    int DoWork();
}
public interface IAction2
{
    string DoWork();
}

public class MyBase : IAction1
{
    public int DoWork() { return 0; }
}
public class MyClass : MyBase, IAction2
{
    public new string DoWork() { return "Hi"; }
}

class Program
{
    static void Main(string[] args)
    {
        var myClass = new MyClass();
        var ret0 = myClass.DoWork(); //Hi
        var ret1 = ((IAction1)myClass).DoWork(); //0
        var ret2 = ((IAction2)myClass).DoWork(); //Hi
        var ret3 = ((MyBase)myClass).DoWork(); //0
        var ret4 = ((MyClass)myClass).DoWork(); //Hi
    }
}

As noted, method/property hiding makes it possible to change things about a method or property which could not be readily changed otherwise. One situation where this can be useful is allowing an inherited class to have read-write properties which are read-only in the base class. For example, suppose a base class has a bunch of read-only properties called Value1-Value40 (of course, a real class would use better names). A sealed descendant of this class has a constructor that takes an object of the base class and copies the values from there; the class does not allow them to be changed after that. A different, inheritable, descendant declare a read-write properties called Value1-Value40 which, when read, behaves the same as the base class versions but, when written, allows the values to be written. The net effect will be that code which wants an instance of the base class that it knows will never change can create a new object of the read-only class, which can copy data from a passed-in object without having to worry whether that object is read-only or read-write.

One annoyance with this approach--perhaps someone can help me out--is that I don't know of a way to both shadow and override a particular property within the same class. Do any of the CLR languages allow that (I use vb 2005)? It would be useful if the base class object and its properties could be abstract, but that would require an intermediate class to override the Value1 to Value40 properties before a descendant class could shadow them.


You are correct that the new keyword explicitly hides a member from the base class so that callers end up using the member in your subclass rather than the superclass version. As that blog post also mentions, you can implicitly do this as well.

That's different than overriding a base class member; to do that the base class member must be marked as abstract or virtual. So not every member on a base class can be overridden. Suppose you're subclassing a class from someone else's assembly and you don't have access to, or don't want to, go back and retrofit that code to make the members virtual. Without the new keyword you would be stuck.

You can argue whether it's better to have the keyword and be explicit (my opinion) or to just do it implicitly.

참고URL : https://stackoverflow.com/questions/3117838/why-do-we-need-the-new-keyword-and-why-is-the-default-behavior-to-hide-and-not-o

반응형