문제
에서 제시티의 프로그래밍 C#(p.142)그는 예를 제공합니다 어디 그를 캐스팅하는 개체는 인터페이스입니다.
interface IStorable
{
...
}
public class Document : IStorable
{
...
}
...
IStorable isDoc = (IStorable) doc;
...
무엇이 포인트이,특히 경우 객체의 클래스를 구현하모버젼은 작동까요?
EDIT1:을 명확히 나에게 관심에 이유에 대한 캐스팅(있을 경우), 지 이유를 구현하기 위한 인터페이스가 있습니다.또한,이 책은 자신의 2001 년 첫 번째 에디션(based on C#1 그러므로 예되지 않을 수 있습과 밀접한 관련 이후 버전에 대한의 C#).
EDIT2:추가 어떤 상황에 맞는 코드
해결책
실제로 캐스트가 필요할 때의 이유는 하나뿐입니다. Doc이 기본 유형의 실제 객체 일 때 istorable을 구현하는 경우. 설명하겠습니다 :
public class DocBase
{
public virtual void DoSomething()
{
}
}
public class Document : DocBase, IStorable
{
public override void DoSomething()
{
// Some implementation
base.DoSomething();
}
#region IStorable Members
public void Store()
{
// Implement this one aswell..
throw new NotImplementedException();
}
#endregion
}
public class Program
{
static void Main()
{
DocBase doc = new Document();
// Now you will need a cast to reach IStorable members
IStorable storable = (IStorable)doc;
}
}
public interface IStorable
{
void Store();
}
다른 팁
인터페이스에서 제공하는 방법으로만 자신을 제한하고 싶기 때문입니다. 클래스를 사용하는 경우 인터페이스의 일부가 아닌 메소드 (실수로)를 호출 할 위험이 있습니다.
객체가 인터페이스를 명시 적으로 구현하는 경우 (public void IStorable.StoreThis(...)
) 그 캐스팅은 실제로 인터페이스 멤버에 도달하는 가장 쉬운 방법입니다.
나는이 책에서 어떤 맥락이 그 예를 제시했는지 잘 모르겠습니다. 그러나 일반적으로 여러 상속을 달성하기 위해 객체를 인터페이스에 입력 할 수 있습니다. 아래의 예를 제시했습니다.
public interface IFoo
{
void Display();
}
public interface IBar
{
void Display();
}
public class MyClass : IFoo, IBar
{
void IBar.Display()
{
Console.WriteLine("IBar implementation");
}
void IFoo.Display()
{
Console.WriteLine("IFoo implementation");
}
}
public static void Main()
{
MyClass c = new MyClass();
IBar b = c as IBar;
IFoo f = c as IFoo;
b.Display();
f.Display();
Console.ReadLine();
}
이것은 표시됩니다
IBAR 구현
IFOO 구현
더 많은 맥락 없이는 말하기가 매우 어렵습니다. 변수 인 경우 doc
인터페이스를 구현하는 유형으로 선언되면 캐스트가 중복됩니다.
어떤 버전의 책을 읽고 있습니까? "프로그래밍 C# 3.0"이라면 오늘 밤 집에있을 때 살펴 보겠습니다.
편집 : 지금까지 답변에서 보았 듯이 여기에는 세 가지 잠재적 인 질문이 있습니다.
- 왜 질문에 표시된 진술에서 캐스팅됩니까? (답 : 당신은 할 필요가 없습니다
doc
적절한 컴파일 타임 유형) - 구현 된 인터페이스 또는 기본 클래스에 명시 적으로 캐스트하는 것이 왜 적합합니까? (답 : 다른 답변에 표시된 명시 적 인터페이스 구현, 그리고 캐스트 값을 인수로 전달할 때 덜 구체적인 과부하를 선택하기 위해.)
- 왜 인터페이스를 사용합니까? (답 : 인터페이스 유형으로 작업하면 나중에 콘크리트 유형의 변화가 덜 취약하다는 것을 의미합니다.)
그만큼 doc
객체는 회원을 구현하는 유형 일 수 있습니다. IStorable
명시 적으로, 1 차 인터페이스 클래스에 추가하지 않는다 (즉, 인터페이스를 통해서만 호출 할 수 있음).
실제로 "캐스팅"((t) 구문 사용)는 C#을 핸들링하기 때문에 (예 : F#와 달리) 자동으로 업 캐스트 (캐스트로 캐스트)를 처리하므로 의미가 없습니다.
여기에는 좋은 답변이 많이 있지만 실제로 가장 제한적인 인터페이스를 실제로 사용하고 싶은 이유는 아니라고 생각합니다.
그 이유는 초기 코딩과 관련이 없으며 다음에 코드를 방문하거나 리팩터링 할 때 또는 다른 사람이 할 때 포함됩니다.
버튼을 원하고 화면에 배치한다고 가정 해 봅시다. 버튼이 전달되거나 다른 기능에서 다음과 같은 버튼을 가져오고 있습니다.
Button x=otherObject.getVisibleThingy();
frame.add(x);
Visiblethingy가 버튼이라는 것을 알게됩니다. 버튼을 반환하므로 모든 것이 차가워집니다 (캐스트 필요 없음).
이제 대신 토글 버튼을 반환하기 위해 visiblethingy를 리팩터링한다고 가정 해 봅시다. 구현에 대해 너무 많이 알고 있으므로 이제 방법을 리팩터링해야합니다.
구성 요소 (버튼과 토글의 부모, 인터페이스 일 수있는 모습의 부모-우리 목적을 위해 거의 모든 것이)에만 필요한 방법이 필요합니다.
Component x=(Component)otherObject.getVisibleThingy();
당신은 아무것도 리팩터링 할 필요가 없었을 것입니다. 방금 작동했을 것입니다.
이것은 매우 간단한 경우이지만 훨씬 더 복잡 할 수 있습니다.
따라서 요약은 인터페이스가 필터를 통해 보는 것과 같은 객체를 "보기"하는 특정 방법이라고 생각합니다. 일부 부품 만 볼 수 있습니다. 당신이 당신의 견해를 충분히 제한 할 수 있다면, 객체는 당신의 특정 관점 뒤에 "변형"할 수 있으며 현재 세계의 어떤 것도 영향을 미치지 않을 수 있습니다. 즉, 매우 강력한 추상화 속임수입니다.
인터페이스에 캐스트하는 가장 좋은 이유는 객체에 대한 코드를 작성하고 그들이 어떤 구체적인 유형인지 알지 못하고 원하지 않는 경우입니다.
특정 인터페이스를 구현하는 객체를 발견 할 수 있다는 것을 알고 있다면이 객체의 콘크리트 클래스를 알지 못하고 객체에서 값을 얻을 수 있습니다. 또한 객체가 주어진 인터페이스를 구현한다는 것을 알고 있다면 해당 인터페이스는 객체에서 특정 작업을 수행하기 위해 실행할 수있는 메소드를 정의 할 수 있습니다.
간단한 예는 다음과 같습니다.
public interface IText
{
string Text { get; }
}
public interface ISuperDooper
{
string WhyAmISuperDooper { get; }
}
public class Control
{
public int ID { get; set; }
}
public class TextControl : Control, IText
{
public string Text { get; set; }
}
public class AnotherTextControl : Control, IText
{
public string Text { get; set; }
}
public class SuperDooperControl : Control, ISuperDooper
{
public string WhyAmISuperDooper { get; set; }
}
public class TestProgram
{
static void Main(string[] args)
{
List<Control> controls = new List<Control>
{
new TextControl
{
ID = 1,
Text = "I'm a text control"
},
new AnotherTextControl
{
ID = 2,
Text = "I'm another text control"
},
new SuperDooperControl
{
ID = 3,
WhyAmISuperDooper = "Just Because"
}
};
DoSomething(controls);
}
static void DoSomething(List<Control> controls)
{
foreach(Control control in controls)
{
// write out the ID of the control
Console.WriteLine("ID: {0}", control.ID);
// if this control is a Text control, get the text value from it.
if (control is IText)
Console.WriteLine("Text: {0}", ((IText)control).Text);
// if this control is a SuperDooperControl control, get why
if (control is ISuperDooper)
Console.WriteLine("Text: {0}",
((ISuperDooper)control).WhyAmISuperDooper);
}
}
}
이 작은 프로그램을 실행하면 다음과 같은 출력이 제공됩니다.
ID : 1
텍스트 : 저는 텍스트 제어입니다
ID : 2
텍스트 : 저는 또 다른 텍스트 컨트롤입니다
ID : 3
텍스트 : 그냥
콘크리트 객체 유형으로 작업 한 모든 객체에 대해 아무것도 알아야하는 DoMething Method에서 코드를 작성할 필요가 없었습니다. 내가 아는 유일한 것은 내가 제어 클래스의 인스턴스 인 객체를 작업한다는 것입니다. 그런 다음 인터페이스를 사용하여 다른 것을 찾을 수 있습니다.
객체의 인터페이스를 사용 하여이 접근 방식을 취하는 백만 가지 이유가 있지만 정확히 무엇이 있는지 정확히 알지 못하고 객체에 액세스 할 수있는 느슨한 방법을 제공합니다.
세계의 모든 신용 카드를 생각해보십시오. 모든 회사는 자체적으로 만들어지고 인터페이스는 동일하므로 모든 카드 리더는 표준을 따르는 카드를 통해 카드를 스 와이프 할 수 있습니다. 인터페이스 사용과 유사합니다.
언급 된 바와 같이, 캐스팅은 불필요하며 필요하지 않습니다. 그러나 그것은 초보자들이 그들의 이해를 돕는 데 유용한 더 명백한 코딩 형태입니다.
입문 교과서에서, 불만 제가 신뢰할 수있는 일을 암시 적으로 수행하게하기보다는 명시 적으로 행동하는 것이 가장 좋습니다. 이는 초보자에게 더 혼란 스러울 것입니다.
"Doc"은 유형의 유형이 아니기 때문에 초보자가 ISDOC에 할당되고 있음을 알게 될 것입니다. 저자 (책과 코드의)는 명시 적으로 캐스팅함으로써 문서가 istorable 객체에 캐스팅 될 수 있지만 istorable 객체와 동일하지 않다고 말합니다.
요점은, 대상 (어디서 얻었습니까?) 5 월 ~ 아니다 인터페이스를 구현하고,이 경우 예외가 발생하여 잡을 수 있습니다. 물론 "IS"연산자를 사용하여 확인할 수 있으며 C 스타일 캐스트 대신 캐스트를하는 "AS"연산자를 사용할 수 있습니다.
을 허용하는 가장 간 분리 코드 조각...
다음과 같은 문서에 대한 더 많은:인터페이스