your programing

C #-공개적으로 상속 된 메서드를 숨길 수 있음 (예 : 파생 클래스에 대해 비공개로 설정)

lovepro 2020. 12. 29. 08:06
반응형

C #-공개적으로 상속 된 메서드를 숨길 수 있음 (예 : 파생 클래스에 대해 비공개로 설정)


공용 메서드 A와 B가있는 BaseClass가 있고 상속을 통해 DerivedClass를 생성한다고 가정합니다.

예 :

public DerivedClass : BaseClass {}

이제 A와 B를 사용하는 DerivedClass에서 메서드 C를 개발하려고합니다. DerivedClass에서 메서드 C 만 내 DerivedClass를 사용하려는 사람에게 노출되도록 메서드 A와 B를 비공개로 재정의 할 수있는 방법이 있습니까?


불가능 해, 왜?

C #에서는 공용 메서드를 상속하는 경우 해당 메서드를 공용으로 만들어야합니다. 그렇지 않으면 그들은 당신이 처음에 클래스에서 파생되지 않기를 기대합니다.

is-a 관계를 사용하는 대신 has-a 관계를 사용해야합니다.

언어 디자이너는 상속을 더 적절하게 사용하기 위해 의도적으로 이것을 허용하지 않습니다.

예를 들어 실수로 Car 클래스를 혼동하여 기능을 얻기 위해 Engine 클래스에서 파생 할 수 있습니다. 그러나 엔진은 자동차에서 사용하는 기능입니다. 따라서 has-a 관계를 사용하고 싶을 것입니다. 자동차 사용자는 엔진 인터페이스에 대한 액세스를 원하지 않습니다. 그리고 자동차 자체는 엔진의 방법과 그것의 방법을 혼동해서는 안됩니다. Car의 미래 파생도 아닙니다.

따라서 잘못된 상속 계층으로부터 사용자를 보호하지 못합니다.

대신 무엇을해야합니까?

대신 인터페이스를 구현해야합니다. 이렇게하면 has-a 관계를 사용하여 기능을 자유롭게 사용할 수 있습니다.

다른 언어 :

C ++에서는 private, public 또는 protected의 기본 클래스 앞에 수정자를 지정하기 만하면됩니다. 이렇게하면 지정된 액세스 수준에 대해 공개 된 기본 구성원이 모두 만들어집니다. C #에서 똑같이 할 수 없다는 것이 나에게는 어리석은 것 같습니다.

재구성 된 코드 :

interface I
{
    void C();
}

class BaseClass
{
    public void A() { MessageBox.Show("A"); }
    public void B() { MessageBox.Show("B"); }
}

class Derived : I
{
    public void C()
    {
        b.A();
        b.B();
    }

    private BaseClass b;
}

나는 위의 클래스 이름이 약간의 논쟁이라는 것을 이해합니다. :)

기타 제안 :

다른 사람들은 A ()와 B ()를 공개하고 예외를 던지도록 제안했습니다. 그러나 이것은 사람들이 사용하기에 친숙한 수업이 아니며 실제로 의미가 없습니다.


예를 들어에서 상속하려고 할 List<object>때 직접 Add(object _ob)멤버 를 숨기고 싶을 때 :

// the only way to hide
[Obsolete("This is not supported in this class.", true)]
public new void Add(object _ob)
{
    throw NotImplementedException("Don't use!!");
}

실제로 가장 바람직한 솔루션은 아니지만 작업을 수행합니다. Intellisense는 여전히 허용하지만 컴파일 타임에 오류가 발생합니다.

오류 CS0619 : 'TestConsole.TestClass.Add (TestConsole.TestObject)'는 더 이상 사용되지 않습니다. '이 클래스에서는 지원되지 않습니다.'


나쁜 생각 같네요. Liskov 는 감동하지 않을 것입니다.

DerivedClass의 소비자가 메서드 DeriveClass.A () 및 DerivedClass.B ()에 액세스 할 수 없도록하려면 DerivedClass가 일부 공용 인터페이스 IWhateverMethodCIsAbout을 구현해야하고 DerivedClass의 소비자는 실제로 IWhateverMethodCIsAbout과 대화해야하며 알고 있어야합니다. BaseClass 또는 DerivedClass의 구현에 대해서는 전혀 없습니다.


필요한 것은 상속이 아닌 구성입니다.

class Plane
{
  public Fly() { .. }
  public string GetPilot() {...}
}

Now if you need a special kind of Plane, such as one that has PairOfWings = 2 but otherwise does everything a plane can.. You inherit plane. By this you declare that your derivation meets the contract of the base class and can be substituted without blinking wherever a base class is expected. e.g. LogFlight(Plane) would continue to work with a BiPlane instance.

However if you just need the Fly behavior for a new Bird you want to create and are not willing to support the complete base class contract, you compose instead. In this case, refactor the behavior of methods to reuse into a new type Flight. Now create and hold references to this class in both Plane and Bird. You don't inherit because the Bird does not support the complete base class contract... ( e.g. it cannot provide GetPilot() ).

같은 이유로, ..재정의 할 때 기본 클래스 메서드의 가시성을 줄일 수 없습니다. 파생에서 기본 개인 메서드를 재정의하고 공용으로 만들 수 있지만 그 반대의 경우도 마찬가지입니다. 예를 들어이 예제에서 Plane "BadPlane"유형을 파생 한 다음 GetPilot ()을 재정의하고 "숨기기"하면-비공개로 설정합니다. 클라이언트 메서드 LogFlight (Plane p)는 대부분의 Planes에서 작동하지만 LogFlight 구현에 GetPilot ()이 필요 / 호출되는 경우 "BadPlane"에 대해 폭발합니다. 기본 클래스의 모든 파생은 기본 클래스 매개 변수가 예상되는 모든 곳에서 '대체 가능'할 것으로 예상되므로이를 허용하지 않아야합니다.


내가 아는 유일한 방법은 Has-A 관계를 사용하고 노출하려는 함수 만 구현하는 것입니다.


@Brian R. Bondy는 상속과 새로운 키워드를 통한 숨기기에 관한 흥미로운 기사를 알려주었습니다 .

http://msdn.microsoft.com/en-us/library/aa691135(VS.71).aspx

따라서 해결 방법으로 다음을 제안합니다.

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

    public void B()
    {
        Console.WriteLine("BaseClass.B");
    }
}

class DerivedClass : BaseClass
{
    new public void A()
    {
        throw new NotSupportedException();
    }

    new public void B()
    {
        throw new NotSupportedException();
    }

    public void C()
    {
        base.A();
        base.B();
    }
}

이런 식으로 다음과 같은 코드는 NotSupportedException을 발생시킵니다 .

    DerivedClass d = new DerivedClass();
    d.A();

숨어있는 것은 꽤 미끄러운 경사입니다. 주요 문제인 IMO는 다음과 같습니다.

  • 인스턴스의 디자인 타임 선언 유형에 따라 다릅니다. 즉, BaseClass obj = new SubClass ()와 같은 작업을 수행 한 다음 obj.A ()를 호출하면 숨김이 실패합니다. BaseClass.A ()가 실행됩니다.

  • 숨기기는 기본 유형의 동작 (또는 동작 변경)을 매우 쉽게 가릴 수 있습니다. 방정식의 양쪽을 모두 소유하거나 'base.xxx'를 호출하는 것이 하위 멤버의 일부인 경우에는 분명히 걱정할 필요가 없습니다.

  • If you actually do own both sides of the base/sub-class equation, then you should be able to devise a more manageable solution than institutionalized hiding/shadowing.

I would say that if you have a codebase that you are wanting to do this with, it is not the best designed code base. It's typically a sign of a class in one level of the heirarchy needing a certain public signature while another class derived from that class doesn't need it.

An upcoming coding paradigm is called "Composition over Inheritance." This plays directly off of the principles of object-oriented development (especially the Single Responsibility Principle and Open/Closed Principle).

Unfortunately, the way a lot of us developers were taught object-orientation, we have formed a habit of immediately thinking about inheritance instead of composition. We tend to have larger classes that have many different responsibilities simply because they might be contained with the same "Real World" object. This can lead to class hierarchies that are 5+ levels deep.

An unfortunate side-effect that developers don't normally think about when dealing with inheritance is that inheritance forms one of the strongest forms of dependencies that you can ever introduce into your code. Your derived class is now strongly dependant on the class it was inherited from. This can make your code more brittle in the long run and lead to confounding problems where changing a certain behavior in a base class breaks derived classes in obscure ways.

One way to break your code up is through interfaces like mentioned in another answer. This is a smart thing to do anyways as you want a class's external dependencies to bind to abstractions, not concrete/derived types. This allows you to change the implementation without changing the interface, all without effecting a line of code in your dependent class.

I would much rather than maintain a system with hundreds/thousands/even more classes that are all small and loosely-coupled, than deal with a system that makes heavy use of polymorphism/inheritance and has fewer classes that are more tightly coupled.

Perhaps the best resource out there on object-oriented development is Robert C. Martin's book, Agile Software Development, Principles, Patterns, and Practices.


If they're defined public in the original class, you cannot override them to be private in your derived class. However, you could make the public method throw an exception and implement your own private function.

Edit: Jorge Ferreira is correct.


While the answer to the question is "no", there is one tip I wish to point out for others arriving here (given that the OP was sort of alluding to assembly access by 3rd parties). When others reference an assembly, Visual Studio should be honoring the following attribute so it will not show in intellisense (hidden, but can STILL be called, so beware):

[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]

If you had no other choice, you should be able to use new on a method that hides a base type method, return => throw new NotSupportedException();, and combine it with the attribute above.

Another trick depends on NOT inheriting from a base class if possible, where the base has a corresponding interface (such as IList<T> for List<T>). Implementing interfaces "explicitly" will also hide those methods from intellisense on the class type. For example:

public class GoodForNothing: IDisposable
{
    void IDisposable.Dispose() { ... }
}

In the case of var obj = new GoodForNothing(), the Dispose() method will not be available on obj. However, it WILL be available to anyone who explicitly type-casts obj to IDisposable.

In addition, you could also wrap a base type instead of inheriting from it, then hide some methods:

public class MyList<T> : IList<T>
{
    List<T> _Items = new List<T>();
    public T this[int index] => _Items[index];
    public int Count => _Items.Count;
    public void Add(T item) => _Items.Add(item);
    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
    void ICollection<T>.Clear() => throw new InvalidOperationException("No you may not!"); // (hidden)
    /*...etc...*/
}

ReferenceURL : https://stackoverflow.com/questions/106383/c-sharp-can-publicly-inherited-methods-be-hidden-e-g-made-private-to-derived

반응형