인터페이스에서 정적 메서드를 어떻게 구현할 수 있습니까?


92

C #에서 호출하는 타사 C ++ DLL이 있습니다.

메서드는 정적입니다.

일부 단위 테스트를 수행하기 위해 추상화하고 싶으므로 정적 메서드로 인터페이스를 만들었지 만 이제 프로그램 오류는 다음과 같습니다.

수정 자 '정적'은이 항목에 유효하지 않습니다.

MyMethod cannot be accessed with an instance reference; qualify it with a type name instead

이 추상화를 어떻게 얻을 수 있습니까?

내 코드는 다음과 같습니다.

private IInterfaceWithStaticMethods MyInterface;

public MyClass(IInterfaceWithStaticMethods myInterface)
{
  this.MyInterface = myInterface;
}

public void MyMethod()
{
  MyInterface.StaticMethod();
}

3
확장 메서드를 사용하여 할 수 있습니다 : stackoverflow.com/questions/1243921/…
hcb

답변:


47

C #의 인터페이스에는 정적 멤버를 정의 할 수 없습니다. 인터페이스는 인스턴스에 대한 계약 입니다 .

현재 상태 그대로 인터페이스를 만드는 것이 좋지만 static 키워드는 사용하지 않는 것이 좋습니다. 그런 다음 StaticIInterface인터페이스를 구현하고 정적 C ++ 메서드를 호출 하는 클래스 를 만듭니다 . 단위 테스트를 수행하려면 FakeIInterface인터페이스도 구현하지만 단위 테스트를 처리하는 데 필요한 작업을 수행하는 다른 클래스를 만듭니다 .

이 두 가지 클래스를 정의한 후에는 환경에 필요한 클래스를 만들고 MyClass의 생성자에 전달할 수 있습니다.


64
-1 말에 대한 An interface is a contract, not an implementation.- 사실, 그러나 (완전히 무관하다는 불합리한 추론 하기 때문에,) 여기 정적 메소드 구현 자체의 일부가 아닌 - 구현, 정의에 의해, 기반으로 데이터를 차례로이다, 접근 할 수없는 정적 멤버합니다. An interface type definition can define and implement static methods (see §8.4.3) since static methods are associated with the interface type itself rather than with any value of the type.- static멤버는 일반적으로 유틸리티 메서드 라는 것을 명심하십시오 .

2
나는 귀하의 진술을 이해하고 이에 동의하며 귀하의 의견도 중요한 맥락이라고 생각합니다. 이기는 하지만. 인터페이스를 디자인 할 때는이를 계약으로 생각해야합니다. 이는 정적 메서드가 적용되지 않음을 의미합니다. 나는 일부 사람들이 인터페이스의 목적을 이해하도록 돕기 위해 그것을 남겨 두어야한다고 생각했습니다. 커뮤니티에서 제거해야한다고 생각합니까?
davisoa

1
나는 그것이 An interface is a contract, not an implementation쓸모가 없다는 것에 부분적으로 동의하고 때로는 약간의 상황 화가 정말 도움이됩니다. 그리고 저는 완전히 동의합니다 static method is not a part of implementation itself . 정적 메서드 구현이 있으며 다른 메서드의 구현에서 구현으로 사용되는 경우에만 구현의 일부가됩니다. 그러나 내 사전은 내가 아는 한, 프로그래밍 언어에 따라 용어가 실제로 다릅니다. 어쨌든 하나의 구현 만있을 수 있기 때문에 정적 메서드는 인터페이스가 될 수 없습니다.
CoffeDeveloper

그 사람의 출신 국가 이름을 제공 IPerson한다는 계약이 있다고 가정 해 봅시다 GetCountry. FrenchPerson엔티티는 모두 "France" GermanPerson라고 말하고 모두 "Germany"라고 말하며 MS와 같은 다른 유형의 엔티티가 동일한 (데이터) 테이블을 공유 할 때도 유용합니다. 푸른 하나, 말 Connection, Post그리고 Comment에 저장되어있는 Users트리 개체가 공유 정보를 가지고 있으므로, AzureTable IUsers가질 수 GetTableName정적 방법을 ...
서지

@vaxquis-IMHO, "그것의 계약"은 문장이 바뀌었다면 관련이있을 것입니다 : ʻ 인터페이스는 인스턴스를 위한 계약 입니다 . 정적 멤버는 유형의 일부입니다. 이 문장은 인스턴스 계약에서 의미가 없다고 (올바르게) 말합니다. 그래서 문제는 불공평 한 표현이 아니라 단지 부정확 한 표현이라고 생각합니다.
ToolmakerSteve

112

인터페이스는 정적 멤버를 가질 수 없으며 정적 메서드는 인터페이스 메서드의 구현으로 사용할 수 없습니다.

할 수있는 일은 명시 적 인터페이스 구현을 사용하는 것입니다.

public interface IMyInterface
{
    void MyMethod();
}

public class MyClass : IMyInterface
{
    static void MyMethod()
    {
    }

    void IMyInterface.MyMethod()
    {
        MyClass.MyMethod();
    }
}

또는 인스턴스 특정 멤버에 액세스하지 않더라도 비 정적 메서드를 사용할 수 있습니다.


18
왜 누군가가 이것을 원하는지 궁금해하는 사람에게는 정적 메서드를 구현하는 레거시 코드에 대한 단위 / 통합 테스트를 작성할 때 특히 유용합니다.
Dezzamondo

이 기술은 데이터를 유지해야하지만 데이터베이스를 사용할 수없는 빠른 RESTful API를 구현하는 데 매우 효과적이었습니다. 구현은 메모리 내 C # 개체로만 작동하므로 데이터를 저장할 장소가 없었지만 정적 속성을 사용하면 EF Core 또는 SQLite를 사용하는 메모리 내 데이터베이스의 필요성이 완화되었습니다.
gware

19

정적 멤버는 C #이 아닌 CLR에서 완벽하게 합법적입니다.

IL에서 접착제를 구현하여 구현 세부 정보를 연결할 수 있습니다.

C # 컴파일러가 호출을 허용하는지 확실하지 않습니까?

참조 : 8.9.4 인터페이스 유형 정의 ECMA-335.

인터페이스 유형은 인터페이스 유형 값의 표현에 대해 아무 말도하지 않기 때문에 반드시 불완전합니다. 이러한 이유로 인터페이스 유형 정의는 정적 필드를 선언 할 수 있지만 (§8.4.3 참조) 인터페이스 유형의 값 (즉, 인스턴스 필드)에 대한 필드 정의를 제공해서는 안됩니다.

유사하게, 인터페이스 유형 정의는 그 유형의 값에 대한 메소드에 대한 구현을 제공하지 않아야합니다. 그러나 인터페이스 유형 정의는 지원 유형에 의해 구현되어야하는 메소드 계약 (메서드 이름 및 메소드 서명)을 정의 할 수 있으며 일반적으로 정의합니다. 인터페이스 형식 정의는 정적 메서드 (§8.4.3 참조)를 정의하고 구현할 수 있습니다. 정적 메서드는 형식의 값이 아닌 인터페이스 형식 자체와 연결되기 때문입니다.


10
참고 CLS Rule 19: CLS-compliant interfaces shall not define static methods, nor shall they define fields.로 CLS 규격 소비자가 이러한 종류의 인터페이스를 거부해도 괜찮다고 말합니다. 나는 약 1 년 전에 인터페이스에서 정적 메서드를 호출하려고 시도했지만 C # 컴파일러는 그것을 컴파일하지 않을 것입니다.
Christopher Currens 2013

CLS에 대한 @ChristopherCurrens 참고 사항 : Common Language Specification (CLS) is a set of basic language features that .Net Languages needed.... When there is a situation to communicate Objects written in different .Net Complaint languages , those objects must expose the features that are common to all the languages. CLS가 서로 다른 .NET 언어 간의 상호 운용성에 관한 것이고 C #이 인터페이스에서 정적 멤버를 허용하지 않는 경우 CLS도이를 금지하여 라이브러리를 다른 .NET 언어는 C #에서 호출 할 수 있습니다.
Simon Tewsi

17

C # 8에서 정적 메서드를 정의 할 수 있지만 이에 대한 기본 본문을 선언해야합니다.

    public interface IMyInterface
    {
          static string GetHello() =>  "Default Hello from interface" ;
          static void WriteWorld() => Console.WriteLine("Writing World from interface");
    }

또는 기본 본문을 원하지 않는 경우 예외를 발생시킵니다.

    public interface IMyInterface
    {
          static string GetHello() =>  throw new NotImplementedException() ;
          static void WriteWorld() => throw new NotImplementedException();
    }

인터페이스의 정적 멤버는 인터페이스 인스턴스로 액세스 할 수 없기 때문에 매우 쓸모없는 것 같습니다. 적어도 C # 8에서는
Pavel Sapehin

3
인터페이스 구현 관점으로, 귀하의 권리. 쓸모가 없습니다. 그러나 이런 식으로 적어도이 인터페이스를 사용하는 모든 클래스에 대해 구현 된 메서드가 있어야합니다. (이것은 인터페이스에 대한 일종의 선택적 구현입니다)
AliReza

5

리플렉션을 사용하여 호출 할 수 있습니다.

MyInterface.GetType().InvokeMember("StaticMethod", BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod, null, null, null);

5
MyInterface 인스턴스가없는 경우 "myInterface.GetType ()"대신 "typeOf (MyInterface)"를 사용할 수 있습니다.
RenniePet

그 당시에는 좋은 생각처럼 보였고, 저는 리플렉션을 통해 계속할 수 있지만, 약간의 경고가 있습니다. 프로그램이 난독 화되어 메서드 StaticMethod의 이름이 바뀌면 더 문제가됩니다.
RenniePet

1
@RenniePet : 대신 nameof (StaticMethod)를 사용하여 StaticMethod 이름 변경을 부분적으로 처리 할 수 ​​있습니다. 이름을 바꾸는 방법에 따라 난독 화기에 도움이 될 수 있습니다. 이렇게하면 적어도 컴파일 시간 오류가 표시됩니다.
Brent Rittenhouse

반영이 경우 너무 극단적
스테판 Ivanenko

3

C # "Ten"은 역할과 함께 인터페이스 에서 정적 멤버를 허용 합니다. 이것은 큰 진전이며, 리플렉션을 사용하지 않고 일반 연산자 오버로딩도 허용합니다. 다음은 "추가 할 수있는 것"을 말하는 전문 용어 인 고전적인 모노 이드 예제를 사용하여 작동 방식의 예제 스 니펫입니다. Mads Torgersen 에서 직접 발췌 : C # into the Future :

interface IMonoid<T>
{
    static T Zero { get; }
    static T operator +(T t1, T t2);
}

public static T AddAll<T>(T[] ts) where T : IMonoid<T>
{
    T result = T.Zero;
    foreach (T t in ts) { result += t; }
    return result;
}

role IntAddMonoid extends int : IMonoid<int>
{
    public static int Zero => 0;
}

IntAddMonoid[] values = new int[] {1, 2, 4, 8, 16, 32};
int sixtyThree = AddAll<IntAddMonoid>(values); // == 63

추가 리소스 :

Jeremy Bytes : C # 8 인터페이스 정적 멤버

편집하다

이 게시물은 원래 인터페이스 정적 멤버가 C # 8.0에 추가 될 것이라고 언급 했는데 이는 사실이 아닙니다. 비디오에서 Mads Torgersen의 말을 잘못 해석했습니다. 공식 C # 8.0 가이드 는 아직 정적 인터페이스 멤버에 대해 이야기하지 않지만, 지금까지 꽤 오랫동안 작업 해 왔음이 분명합니다.


1

인터페이스에 정적 메서드를 사용할 수없는 이유 : C #에서 정적 메서드가 인터페이스를 구현하도록 허용하지 않는 이유는 무엇입니까?

그러나 인스턴스 메서드를 선호하는 정적 메서드를 제거하는 것이 좋습니다. 가능하지 않은 경우 인스턴스 메서드 내부에 정적 메서드 호출을 래핑 한 다음 해당 인터페이스를 만들고 여기에서 단위 테스트를 실행할 수 있습니다.

public static class MyStaticClass
{
    public static void MyStaticMethod()
    {...}
}

public interface IStaticWrapper
{
    void MyMethod();
}

public class MyClass : IStaticWrapper
{
    public void MyMethod()
    {
        MyStaticClass.MyStaticMethod();
    }
}

인터페이스 만 사용하는 것보다 정적 클래스와 함께 인터페이스를 사용하는 이점은 무엇입니까?
Selen

1

C # 8은 인터페이스에서 정적 멤버를 허용합니다.

C # 8.0부터 인터페이스는 멤버에 대한 기본 구현을 정의 할 수 있습니다. 공통 기능에 대한 단일 구현을 제공하기 위해 정적 멤버를 정의 할 수도 있습니다.

인터페이스 (C # 참조)

public interface IGetSomething
{
    public static string Something = "something";
}

var something = IGetSomething.Something;
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.