2009-10-28 5 views
2

나는 인터페이스를 구현하는 객체를 가지고 있습니다. 객체의 메소드가 구현되어 있으면 호출하고 싶습니다. 이 일을하는 가장 좋은 방법은 무엇입니까?C# : Optional method

업데이트 내 질문이 모호하다는 의견이 일부 있습니다. 미안합니다. 내가 "구현된다면"나는 "호출 가능하다면"을 의미했다. 귀하의 답변 및 노력 녀석 (또는 소녀)에 감사드립니다. 나는 얼마나 많은 개발자 지원이이 웹 사이트에 있는지 놀라게한다.

답변

10

이것이 실제로 작동하는 데 필요한 경우 인터페이스는 잘못된 선택입니다. 대신 클래스가 가상 메서드로 파생되는 추상 클래스를 가질 수 있습니다. 가상은 그것을 오버라이드 할 수는 있지만 그것을 필요로하지는 않습니다. 가상 메소드에는 구현이 있으므로 인터페이스의 일부가 될 수 없습니다. 객체도이 같은 인터페이스를 구현하는 경우 P

당신은 확인할 수 있습니다 :

+1

하위 클래스에는 여전히 가상 메소드 구현이 있습니다. 기본 클래스 구현입니다. –

12

"구현 된 경우"의 의미가 확실하지 않습니다. 메서드가 인터페이스에 있고 개체가 인터페이스를 구현하는 경우 메서드를 구현해야합니다.

+0

구현이 있어야하지만 NotImplementedException을 던져서 사실 구현이 가능하지 않다는 것을 알 수 있습니다. 예를 들어 프레임 워크에서'Stream' 클래스를 봅니다 (이것은 인터페이스이지만 추상 클래스이지만 개념은 둘 다 동일합니다. – Lucero

+1

하지만 컴파일러에 관한 한 여전히 구현되는 방법이 있으므로 질문은 무엇입니까? –

+1

구현 (코드에서 호출 가능)과 구현 (논리적으로는 객체가 작업을 지원하는 것)간에 혼란이 있다고 생각합니다. 내 생각 엔 질문의 저자는 후자를 의미합니다. – Lucero

2

개체의 클래스가 인터페이스의 모든 메서드를 구현하면 안됩니까?

개체의 클래스가 추상 클래스에서 상속되는 경우 일부 메서드를 재정의 (구현)하지 않을 수도 있습니다. 아마 당신은 당신의 마음에 두 가지를 혼합하고 있습니다.

7

두 개의 인터페이스를 만들고 모든 메서드가 필요한 두 인터페이스를 상속합니다. 옵션 인 메서드가 필요하지 않은 인터페이스 중 하나만 상속합니다. OOP 용으로 모든 인터페이스가 상속 할 기본 인터페이스를 만들 수도 있습니다. 당신이 메서드를 호출 할 수 있도록 객체가 인터페이스를 구현하는 경우 테스트하려면

10

, 당신과 같이 그것을 할 수 있습니다 :

interface IFoo { void Bar(); } 

object o = GetObjectThatMayImplementIFoo(); 
IFoo foo = o as IFoo; 

if (foo != null) { 
    foo.Bar(); 
} 

내가 그건 당신이 요구 한 무슨 생각?

+3

''is''와''cast'' 패턴은 사용하지 않는 것이 좋습니다.'as'를 사용하고'null'을 검사해야합니다. 런타임은 두 개의 타입 변환을 수행하지 않으므로 성능이 좋습니다. – Lucero

+0

사실, 나는 그 자신을 사용하지 않는다. 왜 그런 식으로 그 예를 썼는지 확신 할 수 없다. 업데이트 됨! – wojo

+0

Perfect, +1 for you ...;) – Lucero

2

다른 답변과 마찬가지로, 나는 당신이 무슨 뜻인지 모르겠다. 인터페이스를 구현하는 클래스가 인터페이스 메소드 중 하나를 구현하지 못하게 할 수있는 가장 가까운 것은 NotImplementedException을 던지는 것입니다. 이 문제를 처리하는 방법은 메서드를 호출 할 때 해당 예외를 특히 catch하는 것입니다. 그러나 인터페이스의 핵심은 클래스 간의 계약을 정의하는 것이므로 어쩌면 일부 설명이 도움이 될 수 있습니다.

1

실제로 메소드가 구현되는지 (또는 클래스가 단지 "더미"구현을 가졌는지) 알 수 없습니다. 따라서 다음 중 하나와 같은 패턴을 사용하여 특정 메서드가 지원되는지 여부를 확인할 수 있습니다.

-> 여러 인터페이스가 있고 클래스에서 실제로 구현되는지 확인합니다. 이것은 아마도 그것을 다루는 가장 깨끗한 방법이지만, 그것은 바람직하지 않을 수있다 서로 다른 인터페이스의 많은 수의, 당신을 떠날 수

IIntfA = inst as IIntfA; 
if (inst != null) { 
    // inst seems to be implemented 
} 

- TryXxx 스타일> 사용 방법, 경우에 true를 돌려줍니다 그들은 성공했습니다 (예 : TryParse() 등).

->NotImplementedException을 사용하십시오. 그러나 그 값을 잡는 것은 비용이 많이 들며 거의 수행되지 않는 호출이나 누락 된 구현이 예상되지 않는 호출에만 사용해야합니다. Stream 클래스는 이와 같이 작동합니다 (예 : 쓸 수없는 경우).하지만 클래스가 지원하는 속성 (예 : , Stream 클래스)도 지원됩니다.

+1

변수 이름이 누락되었습니다 –

2

첫 번째 응답은이 작업을 수행하지 않습니다. 그것은 메소드가 존재할 가능성을 둘러싼 조건부 로직을 생성하고, C#의 정적으로 형체에 위배됩니다. 그리고 몇 가지 솔리드 원칙을 깨뜨립니다. 내 경험에 따르면 이것이 걷는 잘못된 길임을 알 수 있습니다.

Reflection 또는 wojo가 보여주는 'is/as'솔루션을 사용하여 수행 할 수 있습니다.

이 유형의 동작은 동적 언어에서 더 잘 구현 될 수 있습니다. Duck 타이핑과 비슷합니다. 나는 역동적 인 언어 사람이 아니지만 단위 테스트가 있다면 괜찮을 것입니다.

1

얘들 아가는 것을 잊지 마세요 키워드가 ""

if (inst is IInterface) 
{ 
    // you can safely cast it 
} 

나는 그런 식하지만 물론 선호 당신은 또한 "같이"키워드를 사용할 수 있습니다

IInterface a = inst as IInterface; 
if (a != null) 
{ 
    // use a, already casted 
} 
4

나는 당신이 정말로 찾고있는 것이 부분적인 방법이라고 생각합니다. .NET 3.5의 새로운 기능입니다. 당신은 단순히 "부분"같은 방법을 선언

partial void OnLoaded(); 

방법은 일반적으로 호출 할 수 있습니다

OnLoaded(); 

깔끔한 것은 방법이 어디 구현되어 있지 않은 경우, 컴파일러가 똑똑하지 않다는 것이다 호출을 생성합니다.

이것은 주로 LINQ to SQL 및 Entity Framework 용으로 구현되었습니다. 이렇게하면 생성 된 코드 (부분 클래스 사용)가 메소드의 구현 여부를 알지 못해도 메소드를 정의하고 호출 할 수 있습니다.

부분적인 메소드를 인터페이스와 혼합하는 것은 흥미로울 것입니다. (시도하지는 않았지만) 첫 번째 시도는 인터페이스의 부분 메소드를 선언 할 것입니다.

+0

+1. 이 대답은 내 직감이 떠오른 이유입니다. – Brian

+3

나는 그것이 그가 필요로하는 것이 아닌지 의심 스럽다. 부분 메소드는 동일한 클래스의 두 부분 사이에 선택적 "콜백"을 설정하는 데 사용됩니다 (일반적으로 하나가 생성되고 다른 하나는 직접 코딩되는 경우). 그것들은 private, void, return과 같은 많은 제약을 가지고 있습니다. 그들은 인터페이스와는 아무런 관련이 없습니다. –

+0

이들은 부분 클래스에서 생성 된 코드로 작업하기 위해 생성되었습니다. 이것이 적절한 지 여부를 알기위한 원래 포스터의 요구 사항에 대한 충분한 정보가 없습니다. private 메소드에 대한 접근 자로 특성을 설정할 수도 있으므로 "private"가 반드시 단점은 아닙니다. (문제는 속성이 문제의 또 다른 접근 방식 일 수 있습니다.) –

0

나는 이런 식으로 찾고 있을지 모르겠다. 이것은 구현 여부에 관계없이 메소드에 플래그를 지정할 수있는 속성을 사용합니다. 다음으로 인터페이스에 확장 메서드를 추가하여 메서드가 구현되었는지 확인합니다. 마지막으로이 코드는 메서드가 구현되었는지 여부를 객체에 요청할 수있게 해줍니다. 나는 이것을 좋아하지 않지만 그것이 당신이 찾고있는 것일 수 있습니다.

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Reflection; 

namespace ConsoleApplication1 
{ 
    public static class Program 
    { 
     static void Main(string[] args) 
     { 
      EmployeeA empA = new EmployeeA(); 

      if (empA.IsImplemented("TestMethod")) 
       empA.TestMethod(); 

      EmployeeB empB = new EmployeeB(); 
      if (empB.IsImplemented("TestMethod")) 
       empB.TestMethod(); 


      Console.ReadLine(); 

     } 

     public static bool IsImplemented(this IEmp emp, string methodName) 
     { 
      ImplementedAttribute impAtt; 
      MethodInfo info = emp.GetType().GetMethod(methodName); 
      impAtt = Attribute.GetCustomAttribute(info, typeof(ImplementedAttribute), false) 
         as ImplementedAttribute; 

      return (impAtt == null) ? true : impAtt.Implemented; 

     } 

    } 

    public class EmployeeA : IEmp 
    { 
     #region IEmp Members 

     [Implemented(false)] 
     public void TestMethod() 
     { 
      Console.WriteLine("Inside of EmployeeA"); 
     } 

     #endregion 
    } 

    public class EmployeeB : IEmp 
    { 
     #region IEmp Members 

     [Implemented(true)] 
     public void TestMethod() 
     { 
      Console.WriteLine("Inside of EmployeeB"); 
     } 

     #endregion 
    } 


    public class ImplementedAttribute : Attribute 
    { 
     public bool Implemented { get; set; } 

     public ImplementedAttribute():this(true) 
     { 
     } 

     public ImplementedAttribute(bool implemented) 
     { 
      Implemented = implemented; 
     } 
    } 

    public interface IEmp 
    { 
     void TestMethod(); 
    } 

} 

편집 : 원저자가 질문을 수정 한 후에, 당신은 분명히 그 인터페이스가 어떻게 존재 하는지를 구현하고 싶습니다. 내가 호기심에 위의 코드를 남길 것이다.

+0

감사합니다! 매우 흥미로운 해결책. – burnt1ce

0

개체를 참조하는 방법에 따라 특정 멤버가 표시됩니다. 인터페이스는 암시 적으로 정의되거나 명시 적으로 정의되거나 파생 된 클래스로 구현 될 수 있으며 기본 클래스 참조를 사용합니다. 즉, 개체에서 사용 가능한 모든 멤버가 항상 즉시 나타나는 것은 아닙니다.

개체 (yourObj)에 의한 특정 인터페이스 (ISomething)의 구현을 테스트하려면 리플렉션을 사용하여 데이터 형식을 테스트하는 것이 좋습니다. 이 테스트의 결과에 따라 명시 적으로 구현 객체를 인터페이스 유형으로 캐스팅하고 해당 멤버를 사용할 수 있습니다.

if (yourObj is ISomething) 
    ((ISomething)yourObj).DoSomething(); 

이 다른 방법을 수행 같은 일 (메서드 호출을 사용하여 더 많은 "말의")입니다 :

public interface ISomething { 
    void DoSomething(); 
    // other members ... 
} 

에서 :

if (typeof(ISomething).IsAssignableFrom(yourObj.GetType())) 
    ((ISomething)yourObj).DoSomething(); 

이 샘플은 ISomething 인터페이스를 가정은 다음과 같이 정의된다 요약,이 코드는 다음과 같이 말합니다 : 인터페이스가 무언가가 지정 가능한 경우 - 선택한 객체에서 객체가 해당 인터페이스를 구현하므로 해당 공용 멤버가 있습니다.