문제

이걸 고려하세요:

public class interface Person : IPerson
{
  int ID { get; protected set; }
  string FirstName { get; set; }
  string LastName { get; set; }
  string FullName { get { return FirstName + " " + LastName; } }
}

이:

public class StubPerson : IPerson
{
    int ID { get { return 0; protected set { } }
    string FirstName { get { return "Test" } set { } }
    string LastName { get { return "User" } set { } }
    string FullName { get { return FirstName + " " + LastName; } }
}

용법:

IPerson iperson = new Person();

또는:

IPerson ipersonStub = new StubPerson();

또는:

IPerson ipersonMock = mocks.CreateMock<IPerson>();

사실상 우리는 선언하고 있습니다 iPerson 인터페이스와 사람 동시에 수업 :

public class interface Person : IPerson

.NET/C#에서 이런 종류의 지원을받는 것이 유용 할 것이라고 생각하십니까?

편집하다:

대량 혼란으로 인해 제안 된 목적을 명확히해야한다고 생각합니다.

이 기능이 없으면 다음을 작성해야합니다.

interface IPerson
{
  int ID { get; }
  string FirstName { get; set; }
  string LastName { get; set; }
  string FullName { get; }
}

뿐만 아니라 :

public class Person : IPerson
{
  int ID { get; protected set; }
  string FirstName { get; set; }
  string LastName { get; set; }
  string FullName { get { return FirstName + " " + LastName; } }
}

나는 의미 론적 변화를 전혀 제안하지 않습니다.

도움이 되었습니까?

해결책

나는 고려했다 얼마 전에 같은 종류의 것, 특히 인터페이스를 하나의 프로덕션 구현 만 구현하는 경우에 사용하지만 테스트를 위해이를 조롱하려는 경우. 현재 그것은 요로의 .c/.h 파일과 약간 비슷합니다.

결국 그 이점이 언어에서 추가 복잡성과 나중에 코드를 읽는 것보다 더 중요하다고 생각합니다. 그래도 나는 그것이 더 철저하게 탐구하는 데 관심이 있습니다. 그럼에도 불구하고 우선 순위 목록에는 다른 것들이 더 높아집니다. 불변성에 대한 더 나은 지원은 맨 위에 있습니다 :)

다른 팁

내가 당신이 묻는 것을 이해하고 있는지 확인하겠습니다.

인터페이스를 선언 할 수없는 이유 :

interface IPerson
{
    string Name {get;set;}
    int ID {get;set;}
}

그리고 해당 인터페이스를 구현하는 클래스는 재산을 다시 해제하지 않고 속성을 상속합니다.

class Person : IPerson { } 
//person now has properties Name and ID

이 작업을 수행 할 수없는 이유는 인터페이스 코드와 클래스 코드의 텍스트가 매우 유사하더라도 매우 의미가 있습니다 다른 것들. 인터페이스는 단순히 "구현자가 getter and setter가있는 문자열 이름을 갖습니다"라고 말합니다. "Getter for Name이 호출 될 때 개인 필드를 반환하십시오."라고 말하는 것은 클래스입니다. Auto-Property Shortcut을 사용하여 컴파일러가 해당 논리를 구현하도록하더라도 여전히 논리, 수업에 속한다. 으니까:

string Name {get;set;}

외모 인터페이스와 클래스에서도 동일한다고해서 원격으로 동일한 것을 의미하지는 않습니다.

컴파일이 당신이 그들을 구현하지 않은 컴파일 시간에 불만을 제기하는 대신, 컴파일러가 계약을 이행하기 위해 임의의 논리를 구현하는 것은 매우 위험합니다. 추적하기가 매우 어려운 버그를 도입 할 수 있습니다. 동작이 정의되지 않을 때 컴파일러가 기본 동작으로 돌아 가지 않는 것은 매우 나쁜 생각입니다.

나는 Eiffel이 여러 상속을 지원하기 위해 .NET에서 이와 같은 일을한다고 생각합니다. 클래스 선언은 자동으로 해당 인터페이스를 생성합니다. 클래스 유형을 참조하면 컴파일러는 대부분 인터페이스 유형에 대한 참조를 방출합니다. 주요 예외는 물론 생성자 표현입니다.

다른 대답은 다른 콘크리트 클래스에서 추상 논리에 인터페이스를 사용하는 것을 이해하는 데 도움이 될 것이라고 생각합니다. 또한 Vs에 내장 된 리팩토링 도구를 사용하여 원하는 것과 비슷한 것을 달성 할 수 있다고 생각합니다.

수업 정의 ...

public class Person
{
  public int ID { get; protected set; }
  public string FirstName { get; set; }
  public string LastName { get; set; }
  public string FullName { get { return FirstName + " " + LastName; } }
}

그런 다음 마우스 오른쪽 버튼을 클릭하고 Refactor-> Extrace Interface를 선택하십시오.

이렇게하면 클래스의 정의를위한 인터페이스가 포함 된 별도의 파일이 생겨서 인터페이스를 만들고 클래스를 구현할 수 있습니다.

추출 된 인터페이스 :

interface IPerson
{
    string FirstName { get; set; }
    string FullName { get; }
    int ID { get; }
    string LastName { get; set; }
}

나는 요점을 놓친 것 같아요 - 수업과 인터페이스를 함께 혼합하여 무엇을 성취하고 있습니까? 이 접근법으로 어떤 문제를 해결하고 있습니까?

이것:

IPerson iperson = new Person();

C#에서 이미 합법적입니다.

편집하다: 설명을 위해 - 위의 코드는 다음과 같이 합법적입니다.

interface IPerson { }

class Person : IPerson { }

나는 최소한 Visual Studio를 좋아한다.

불행히도이 옵션은 그렇지 않으며 구현되지 않은 예외 스텁을 처리해야합니다.

아니요, 인터페이스의 모든 공개 구성원을 노출해야하기 때문입니다. 노력하다 resharper, 그리고 이것에 대해 다시는 걱정하지 마십시오.

Resharper는이 기능을 제공 할 수 있습니다.

  1. 먼저 개인 수업을 쓸 수 있습니다.
  2. 인터페이스를 추출 할 수 있습니다 회원을 끌어 당기는 것 iPerson 인터페이스에.

결과적으로 Visual Studio Auto-Generate 구현 스텁을 가질 수 있습니다.

업데이트

어쨌든, 질문에서 제공 한 코드를 인용하여 먼저 인터페이스를 설명해 봅시다.

public class interface Person : IPerson
{
    int ID { get; protected set; }
    string FirstName { get; set; }
    string LastName { get; set; }
    string FullName { get { return FirstName + " " + LastName; } }
}

인터페이스가 추상 클래스가 아니라는 것을 이해해야합니다. 인터페이스는 단지뿐입니다 계약, 일종의 청사진은, 이는 그것이 구현 방법에 대해 실제로 돌보지 않고 다른 객체에서 기대할 내용을 물체에 알려줍니다.

반면에 추상 클래스에는 상속 및 재정의 할 수있는 기능 스 니펫이 포함될 수 있습니다.

위의 경우, "인터페이스"가 유효하지 않습니다.

  • 구현 세부 사항 인 인터페이스 (공개, 개인, 보호, 내부)에서 범위 제약을 선언 할 수 없습니다.
  • 기본 구현을 선언 할 수 없습니다 (예 : FullName 재산) 다시, 그것은 구현 세부 사항이기 때문입니다.

당신이 정말로 정말로 원하는 것은 추상적 인 수업입니다.

public abstract class BasePerson
{
    public abstract int ID { get; protected set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public virtual string FullName { get { return FirstName + " " + LastName; } } 
}

나는 단지 추측하고 있지만 아마도 그것이 당신이 정말로 필요한 것일 수도 있습니다.

업데이트 2

좋아, 나는 당신이 원하는 일을하고 있다고 생각합니다. 그래서 당신이 원하는 것은 이것을 쓸 수 있어야합니다.

public interface IPerson
{
    int ID { get; set; }
    string FirstName { get; set; }
    string LastName { get; set; }
    string FullName { get; }
}

그런 다음 구현을 위해서만 작성하면됩니다.

public class Person : IPerson
{
    public int ID { get; protected set; }
    public string FullName { get { return FirstName + " " + LastName; } } 
}

FirstName 및 LastName 속성을 지정할 필요없이

우리가 다루어야 할 첫 번째 문제는 인터페이스가 구현에서 액세스 구분기를 허용하지 않는다는 사실입니다.

두 번째는 우리의 눈에있는 동안 사실입니다 string FirstName { get; set; } 인터페이스와 public string FirstName { get; set; } 수업에서는 동일하지만 실제로는 그렇지 않습니다.

  • 인터페이스에서 속성 정의는 그 인터페이스를 구현하는 모든 클래스에 Getter 및/또는 Setter 메소드에 대한 메소드 서명이 사용할 수 있음을 나타냅니다.
  • 클래스에서 속성 정의는 CLR에 해당 속성의 값을 보유하는 익명 객체를 만들도록 지시합니다.

프로그래머, 컴파일러의 세계적으로 미묘한 차이.

마지막으로, 인터페이스를 구현할 것을 지정할 때, Visual Studio는 SyncTactic Magic을 수행하여 자동으로 해당 속성 스터브를 만듭니다.

이것에 대한 더 나은 추상화는 특성이라고 생각합니다. 여기, 역할. 이것은 코드와의 인터페이스와 같습니다. 예제는 다음과 같이 코딩 될 수 있습니다.

public role RPerson { 
  int ID { get; protected set; } 
  string FirstName { get; set; } 
  string LastName { get; set; } 
  string FullName { get { return FirstName + " " + LastName; } } 
} 

public class Person : RPerson { }

public class StubPerson : RPerson { 
    int ID { get { return 0; protected set { } } 
    string FirstName { get { return "Test" } set { } } 
    string LastName { get { return "User" } set { } } 
    string FullName { get { return FirstName + " " + LastName; } } 
} 

// ...

RPerson rperson = new Person(); 

RPerson rpersonStub = new StubPerson(); 
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top