비가 상 메서드를 재정의하는 방법이 있습니까? 또는 비슷한 결과를 제공하는 것 (원하는 메서드를 호출하는 새 메서드를 만드는 것 외에)?
Microsoft.Xna.Framework.Graphics.GraphicsDevice
단위 테스트를 염두에두고 메서드를 재정의하고 싶습니다 .
답변
아니요, 가상이 아닌 방법은 재정의 할 수 없습니다. 가장 가까운 new
방법은 동일한 이름 의 메서드를 만들어 메서드를 숨기는 것이지만 좋은 디자인 원칙을 위반하므로 권장되지 않습니다.
그러나 메서드를 숨겨도 진정한 가상 메서드 호출처럼 메서드 호출의 실행 시간 다형성 디스패치가 제공되지 않습니다. 이 예를 고려하십시오.
using System;
class Example
{
static void Main()
{
Foo f = new Foo();
f.M();
Foo b = new Bar();
b.M();
}
}
class Foo
{
public void M()
{
Console.WriteLine("Foo.M");
}
}
class Bar : Foo
{
public new void M()
{
Console.WriteLine("Bar.M");
}
}
이 예제에서는 두 M
메서드 모두 print 메서드를 호출합니다 Foo.M
. 보시다시피이 접근 방식을 사용하면 해당 개체에 대한 참조가 올바른 파생 형식이지만 기본 메서드를 숨기면 다형성 이 중단 되는 한 메서드에 대한 새로운 구현을 가질 수 있습니다 .
이러한 방식으로 기본 메서드를 숨기지 않는 것이 좋습니다.
나는 C #의 기본 동작을 선호하는 사람들에게 메서드가 기본적으로 비가 상 (Java와 반대)이라는 편에서는 경향이 있습니다. 더 나아가서 클래스도 기본적으로 봉인되어야한다고 말하고 싶습니다. 상속은 적절하게 설계하기 어렵고 가상으로 표시되지 않은 메서드가 있다는 사실은 해당 메서드의 작성자가 메서드를 재정의 할 의도가 없음을 나타냅니다.
편집 : “실행 시간 다형성 디스패치” :
이것이 의미하는 바는 가상 메서드를 호출 할 때 실행 시간에 발생하는 기본 동작입니다. 예를 들어 이전 코드 예제에서 비가 상 메서드를 정의하는 대신 실제로 가상 메서드와 실제 재정의 된 메서드도 정의했다고 가정 해 보겠습니다.
이 경우 호출 b.Foo
하면 CLR은 b
참조가 가리키는 개체 유형을 올바르게 결정 Bar
하고 호출을 M
적절하게 전달합니다 .
답변
답변
기본 클래스가 봉인되지 않은 경우이를 상속하여 기본 클래스를 숨기는 새 메서드를 작성할 수 있습니다 (메서드 선언에서 “new”키워드 사용). 그렇지 않으면 재정의하려는 원래 작성자가 아니기 때문에 재정의 할 수 없으므로 가상이 아닙니다.
답변
오버로딩되고 혼란스러워지고 있다고 생각합니다. 오버로딩은 이름이 같지만 매개 변수 집합이 다른 두 개 이상의 메서드가 있음을 의미하고 재정의는 파생 클래스의 메서드에 대해 다른 구현이 있음을 의미합니다 (동작을 대체하거나 수정 함). 기본 클래스).
가상 메서드 인 경우 파생 된 클래스의 override 키워드를 사용하여 재정의 할 수 있습니다. 그러나 비가 상 메서드는 override 키워드 대신 new 키워드를 사용하여 기본 구현 만 숨길 수 있습니다. 컴파일러가 기본 메서드에 대한 정적 디스패치를 사용하므로 호출자가 기본 형식으로 입력 된 변수를 통해 메서드에 액세스하는 경우 비가 상 경로는 쓸모가 없습니다 (즉, 파생 된 클래스의 코드가 호출되지 않음).
기존 클래스에 오버로드를 추가하는 것을 방해하는 것은 없지만 클래스에 대해 알고있는 코드 만 액세스 할 수 있습니다.
답변
CLR을 해킹하지 않고 C # 클래스의 가상이 아닌 메서드를 재정의 할 수 없지만 클래스가 구현하는 모든 인터페이스 메서드를 재정의 할 수 있습니다. 밀봉되지 않은 것으로 간주
class GraphicsDevice: IGraphicsDevice {
public void DoWork() {
Console.WriteLine("GraphicsDevice.DoWork()");
}
}
// with its interface
interface IGraphicsDevice {
void DoWork();
}
// You can't just override DoWork in a child class,
// but if you replace usage of GraphicsDevice to IGraphicsDevice,
// then you can override this method (and, actually, the whole interface).
class MyDevice: GraphicsDevice, IGraphicsDevice {
public new void DoWork() {
Console.WriteLine("MyDevice.DoWork()");
base.DoWork();
}
}
그리고 여기에 데모가 있습니다.
class Program {
static void Main(string[] args) {
IGraphicsDevice real = new GraphicsDevice();
var myObj = new MyDevice();
// demo that interface override works
GraphicsDevice myCastedToBase = myObj;
IGraphicsDevice my = myCastedToBase;
// obvious
Console.WriteLine("Using real GraphicsDevice:");
real.DoWork();
// override
Console.WriteLine("Using overriden GraphicsDevice:");
my.DoWork();
}
}
답변
파생되지 않은 클래스에서 상속하는 경우 추상 슈퍼 클래스를 만들고 대신 다운 스트림에서 상속 할 수 있습니다.
답변
비가 상 메서드를 재정의하는 방법이 있습니까? 또는 비슷한 결과를 제공하는 것 (원하는 메서드를 호출하는 새 메서드를 만드는 것 외에)?
비가 상 메서드는 재정의 할 수 없습니다. 그러나 modifier 키워드를 사용하여 유사한 결과를 얻을 수 있습니다 new
.
class Class0
{
public int Test()
{
return 0;
}
}
class Class1 : Class0
{
public new int Test()
{
return 1;
}
}
. . .
// result of 1
Console.WriteLine(new Class1().Test());
또한 액세스 수정자가 동일한 지 확인해야합니다. 그렇지 않으면 상속을받지 못할 것입니다. 에서 다른 클래스를 상속하는 경우 의 키워드가 영향을 미치지 않습니다 액세스 수정이 동일하지 않는 객체, 그것으로부터 상속.Class1
new
Class1
액세스 수정자가 동일 하지 않은 경우 :
class Class0
{
protected int Test()
{
return 0;
}
}
class Class1 : Class0
{
// different access modifier
new int Test()
{
return 1;
}
}
class Class2 : Class1
{
public int Result()
{
return Test();
}
}
. . .
// result of 0
Console.WriteLine(new Class2().Result());
… 액세스 수정이 경우 대 입니다 같은 :
class Class0
{
protected int Test()
{
return 0;
}
}
class Class1 : Class0
{
// same access modifier
protected new int Test()
{
return 1;
}
}
class Class2 : Class1
{
public int Result()
{
return Test();
}
}
. . .
// result of 1
Console.WriteLine(new Class2().Result());
이전 답변에서 지적했듯이 이것은 좋은 설계 원칙이 아닙니다.