Programing

기본 클래스에서 인터페이스 메서드를 구현할 수있는 이유는 무엇입니까?

crosscheck 2020. 12. 9. 07:51
반응형

기본 클래스에서 인터페이스 메서드를 구현할 수있는 이유는 무엇입니까?


내 프로젝트에서 컴파일 시간 오류가 없기 때문에 C #에서 완전히 유효한 것처럼 보이는 이상한 상황을 발견했습니다.

단순화 된 예는 다음과 같습니다.

using System;
using System.Collections.Generic;

namespace Test
{

    interface IFoo
    {
        void FooMethod();
    }

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

    class B : A, IFoo
    {
    }

    class Program
    {
        static void Main(string[] args)
        {
            IFoo foo = new B();
            foo.FooMethod();
        }
    }
}

이러한 코드가 컴파일됩니다. 그러나,주의 A하지 IFooB구현하지 않는 IFoo방법. 제 경우에는 우연히 (리팩토링 후) A동일한 서명을 가진 메서드가 있습니다. 그런데 왜해야 A구현하는 방법을 알고 FooMethodIFoo인터페이스를? A그것이 IFoo존재 하는지조차 모릅니다 .

나에게 그런 디자인은 위험합니다. 일부 인터페이스를 구현할 때마다이 인터페이스의 각 메서드가 기본 클래스 메서드와 "간섭"하는지 확인해야하기 때문입니다.

이것이 "순수 C # 기능"이라면? 뭐라고 해요? 내가 뭔가를 놓치고 있습니까?


인터페이스의 각 멤버에 대해 컴파일러는 명시 적 구현 (있는 경우)을 찾은 다음 공용 구현 ( 암시 적 구현), 즉 인터페이스 서명과 일치하는 공용 API의 메서드를 찾습니다 . 이 경우 A.FooMethod()공개 구현과 잘 일치하는 것처럼 보입니다. B그 선택이 만족스럽지 않다면 new방법을 사용하거나 명시 적 구현을 ​​사용할 수 있습니다 . 후자가 선호됩니다.

void IFoo.FooMethod() { /* explicit implementation */ }

여기서 핵심 단어는 implements입니다. 기본 클래스 IFoo는 클래스 계층 어딘가의 인터페이스에서 메서드를 구현하는 메서드 서명 에 대해 아무것도 알지 못하지만 선언되었습니다.

따라서 IFoo파생 클래스에서 구현할 때 이미 클래스 구조 내에 구현 된 메서드 서명이 있으므로 다시 구현할 필요가 없습니다.

이 경우 :

interface IFoo
{
  void FooMethod();
}
class A
{
  private void FooMethod(){}
}
class B : A, IFoo
{

}

당신은 구현해야 IFoo때문에이 경우 IFoo구조가 구현되는 시점에서 액세스 할 수없는, 마크 말한대로. IFoo.FooMethod()계층에 이미 정의 된 적절한 메서드 서명이 있음에도 불구하고 구현이 있는지 확인 하여 인터페이스를 암시 적으로 구현할 수 있습니다 .


당신은 코멘트에서 말합니다,

가능성을 그 구현을 쓴 하나 FooMethod에서 A구현하지 않는 클래스를 IFoo실제로 구현하는 의미 IFoo?

글쎄, 그것은 창조 A당시의 사상 작가가 무엇인지는 중요하지 않습니다 A. 둘 다 AND 구현 에서 상속 B된다는 사실에 대해 책임을 져야 하는 작가입니다 . 의 정의의 결과에 대해 생각 하는 것은의 작성자에게 달려 있습니다.BAIFooBB

당신은 또한 말한다

내 경우에는 실수로 (리팩토링 후) A동일한 서명을 사용하는 방법이 있습니다.

suggesting that this situation came about after A and B had both been written. In that case, the situation changes: When editing a class which is *inherited from * (such as A), it is the editor's responsibility to check the effects of the edit on all inheriting classes.


To implement an interface, a class needs only to (a) declare that it is implementing that interface (such as your class B does), and (b) provide implementations for all the methods defined in the interface, either directly or indirectly via a base class (such as your class B does).


Section 13.4.4. of the C# specification states:

Interface mapping for a class or struct C locates an implementation for each member of each interface specified in the base class list of C. The implementation of a particular interface member I.M, where I is the interface in which the member M is declared, is determined by examining each class or struct S, starting with C and repeating for each successive base class of C, until a match is located:

So it seems that this is well defined behavior, as the correct implementation of the FooMethod is not found in B, so a search is performed on its base class A where a method with matching signature is found. This is even explicitly pointed out in the same section of the spec:

The members of a base class participate in interface mapping. In the example

interface Interface1
{
void F();
}
class Class1
{
    public void F() {}
    public void G() {}
}
class Class2: Class1, Interface1
{
    new public void G() {}
}

the method F in Class1 is used in Class2's implementation of Interface1.


The feature is called inheritance. And if you don't like the design, just don't use it. A lot of people dislike inheritance, so you might, either. The definition of inheritance is, that all the members of the base class are also members of the derived one. So there isn't any compiler error. Therefore the Derived implements the contract IFoo provides. It's the base class member, which fulfills this requirement.

The beauty of it is, that you can implement an interface through a base functionality (virtual), which can be overriden if a Derived is expected to behave differently.


Interfaces are not inherited, interfaces are implemented. Thus when you derive a class from an interface, it means

hey interface, you will find a method here which implements the method signiture you have provided.

Since the base class has an implementation of the method, with the same method signiture defined in the interface, there will be no problems.

Even if you write a second interface with including the same method signiture it will still work.

interface IFoo2
{
    void FooMethod();
}

class B : A, IFoo, IFoo2
{
}

"But why should A know how to implement the FooMethod of the IFoo interface? A even doesn't know that IFoo exist."

A doesn't need to know about existence of interface IFoo. Its not A's responsibility to implement FooMethod correctly. Apparently A happened to implement the method which has same signature that of IFoo interface method FooMethod.

Its the responsibility of B to implement FooMethod since it is implementing IFoo interface. But since B is already having a method named FooMethod (inherited from A), it does not need to implement it explicitly. If an inherited method is not doing its job, B can new the method and write its own implementation.


B do implement IFOO. B inherits from A so it actually looks like this:

class B : IFoo  //Notice there is no A here. 
{
    public void FooMethod()
    {
        Console.WriteLine("implementation");
    }
}

And it is clear (from the above code) that B is implementing the IFoo and nothing is special.


While it is not particularly helpful to speculate as to why the creators of C# did what they did, and while I do not like this particular feature, I suspect part of the reason it works as it does is that there is no other good syntax to specify that an interface should be implemented by an already existing base-class method. Requiring that the derived class must define methods that do nothing but chain to the base-class implementation would seem ugly.

That having been said, I think it would have been cleaner for C# to resolve that general problem (interface methods that chain to other members are ugly) by providing a syntax to explicitly attach an interface member to a class member, than use auto-binding semantics to handle one particular situation but require chaining in a more common situation (implementation of interface by protected virtual method):

protected virtual IFoo_Method(int a, int b, int c) { ... }

IFoo.Method(int a, int b, int c) { IFoo_Method(a,b,c); }

While the JITter may be able to figure out that the IFoo_Method call should be in-lined, it really shouldn't have to. It would seem cleaner to declare that the protected method IFoo_Method should be regarded as the implementation of IFoo.Method.

참고URL : https://stackoverflow.com/questions/14703828/why-is-it-possible-to-implement-an-interface-method-in-base-class

반응형