2009-03-13 7 views
2

나는 두 개의 과부하가 걸리는 상황이있다. 나는 어떤 상황이 사실이라면, 나는 과부하 중 하나를 부른다. 그렇지 않으면 나는 다른 것을 부른다. 나는 영리하고 공통된 코드를 객체와 조건을 취하는 단일 일반 메소드로 리팩토링하고 오버로드 된 메소드를 호출하거나 그렇지 않으면 공통 코드를 호출하기로 결정했다.일반 형식의 인스턴스를 다른 강력한 형식의 메서드에 전달할 수 있습니까?

코드의 많은 간단한 예 :

/// <summary> 
/// Dummy interface 
/// </summary> 
public interface ITest1 
{ } 
/// <summary> 
/// Dummy interface 
/// </summary> 
public interface ITest2 
{ } 
/// <summary> 
/// Generic Class 
/// </summary> 
public class GenericClass 
{ 
    /// <summary> 
    /// First overload 
    /// </summary> 
    /// <param name="test1"></param> 
    public void TestMethod(ITest1 test1) 
    { } 
    /// <summary> 
    /// Second overload 
    /// </summary> 
    /// <param name="test2"></param> 
    public void TestMethod(ITest2 test2) 
    { } 

    /// <summary> 
    /// method with common logic 
    /// </summary> 
    /// <typeparam name="TInterfaceType"> 
    /// Type of the test object 
    /// </typeparam> 
    /// <param name="test"> 
    /// Test object to pass to the method. 
    /// </param> 
    public void ConditionallyCallTest<TInterfaceType>(
      TInterfaceType test, bool someLogic) 
    { 
     if (someLogic) 
     { 
      this.TestMethod(test); 
     } 
     else 
     { 
      // .. Perform Common operations here 
     } 
    } 
} 

이 코드 세그먼트를 컴파일하는 경우이, 아무것도하지 않는다는 사실을 무시, 당신은 TInterfaceType을 변환 할 수있는 컴파일러 오류가 발생합니다 ITest1.

내가 그렇게 유형 검사를 할 수있는 유형을 지정 때까지 컴파일러 기다려야 기대했다 :

GenericClass g = new GenericClass(); 
// We have an overload, so this is OK: 
g.ConditionallyCallTest<ITest1>(test1); 
// We have an overload, so this is OK: 
g.ConditionallyCallTest<ITest2>(test2); 
// Compiler error, no overload available: 
g.ConditionallyCallTest<UnknownType>(obj); 

는이 사용하는 C#을 그런 짓을 할 수 있습니까?

또한 허용되는 유형을 지정하기 위해 where 절을 사용하려고했지만 where 절이 지정된 유형과 관계 ​​만 지정하는 방법을 알아낼 수 없었습니다.

편집 그래서이 문제를 해결하기 위해 어떤 다른 제안이, 또는 내가 여기에 언어에 의해 제한하고 내가 mentioned in the comments below, 내가 과부하 방법을 일치 만드는 것을 피하기 위해 시도하는 것처럼

?

+0

에서 상속한다는 인터페이스 IHasTestMethod이 필요하십니까? 아니면 "테스트"라는 가짜 이름입니까? – strager

+0

이것은 실제 코드가 너무 광범위하여 게시 할 수 없기 때문에 문제의 구성 예제 일뿐입니다. –

답변

1

컴파일러는 전달할 내용을 알지 못해도 코드를 컴파일 할 수 있어야합니다. 그리고 "당신의 코드"는이 경우에 해당하는 메서드를 포함하는 클래스를 의미합니다.

즉, 호출을 수행하는 메소드를 컴파일 할 때 알고있는 내용에 따라 TestMethod에 대한 호출이 합법적임을 알아야합니다.

이 경우에는 TInterfaceType에 대해 아무 것도 모르기 때문에 이것이 괜찮다고 보장 할 수 없으므로 불만을 제기합니다.

전혀 문제가 해결되지는 않지만 TInterfaceType 제네릭 형식이 하나 이상의 인터페이스를 구현해야한다는 것을 컴파일러에 알릴 수 있지만 형식이 하나 또는 다른 인터페이스를 구현해야한다고 말할 수는 없습니다.

다른 말로 표현하면, 일부 캐스팅하지 않고는이 작업을 수행 할 수 없습니다.


이렇게하는 한 가지 방법은 지원하려는 각 인터페이스 유형마다 하나씩 여러 개의 오버로드를 만드는 것입니다.

제네릭 형식은 기본적으로 허용되는 형식 집합이 제한된 "모든 형식 가능"입니다.

제네릭을 사용하면 형식이 하나의 인터페이스 나 캐스트를 구현하는지 여부를 명시 적으로 확인하지 않고는이를 수행 할 수 없으므로 명시 적 메서드를 직접 호출해야합니다.

메서드 서명이 제네릭 제약 조건만으로는 달라질 수 없기 때문에이 메서드를 오버로드 할 수 없으며 제네릭 제약 조건에 따라 다릅니다.

+0

나는 그렇게 생각하지 않기를 바란다. :) 나는 이런 식으로 할 수있는 방법이 있는지보기 위해 질문을 확장했다. –

+0

아니요, 없습니다. 컴파일러는 언젠가는 "ConditionallyTest "을 호출하여 처리하는 방법을 찾으려는 희망으로 과부하 된 클래스/메소드를 제공하지 않을 것입니다. 나는 당신이 캐스트없이 이것을 할 수 없다고 말했을 때 그것을 의미했습니다. –

+0

그리고 "이런 일을 할 수있는 방법이 있는지보기 위해서 ...". 예, 있습니다. 인터페이스 지원을 확인하고 적절하게 캐스팅해야합니다. 내가 말했듯이, 캐스트 없이는 할 수 없습니다. 컴파일러가 이런 식으로 당신과 싸우면, 이것이 올바른 방법인지 여부를 그만두고 질문하십시오. –

2

일반적인 방법이 필요합니까?단순한 오버로딩 만 사용하십시오.

/// <summary> 
/// Dummy interface 
/// </summary> 
public interface ITest1 
{ } 
/// <summary> 
/// Dummy interface 
/// </summary> 
public interface ITest2 
{ } 
/// <summary> 
/// Generic Class 
/// </summary> 
public class GenericClass 
{ 
    /// <summary> 
    /// First overload 
    /// </summary> 
    /// <param name="test1"></param> 
    public void TestMethod(ITest1 test1) 
    { } 
    /// <summary> 
    /// Second overload 
    /// </summary> 
    /// <param name="test2"></param> 
    public void TestMethod(ITest2 test2) 
    { } 

    public void ConditionallyCallTest(ITest1 test, bool someLogic) 
    { 
     if(Common(someLogic)) 
      return; 

     TestMethod(test); 
    } 

    public void ConditionallyCallTest(ITest2 test, bool someLogic) 
    { 
     if(Common(someLogic)) 
      return; 

     TestMethod(test); 
    } 

    private bool Common(bool someLogic) 
    { 
     if (someLogic) 
     { 
      return false; 
     } 

     // .. Perform Common operations here 
     return true; 
    } 
} 
+0

유효한 답변과 제가 실제로 가지고있는 솔루션에 가깝지만, 각 과부하에 해당하는 방법을 만들어야하는 것을 피할 수있는 무언가가 있었으면합니다. 나는 그것을 얻는 깨끗하고 쉬운 방법으로 보였으므로 제네릭으로 갔다. 실패했을 때 나의 호기심을 자극했다. –

2

모든 유형에 대한 공통 인터페이스를 추상화하고 이에 대한 다형성을 사용하십시오.

+0

정답입니다. TestMethod는 TInterfaceType에 속하는 다형성 메소드 여야합니다. – mquander

0

나는 IType1과 IType2이 무엇인지 확실하지 않다,하지만 당신은 분명히 그들은 당신이 어떤 종류의 단위 테스트를 작성

interface IType0 { void Foo(); } 
    interface IType1 : IType0 { } 
    interface IType2 : IType0 { } 

    void ConditionalCall(IType0 type, bool cond) 
    { 
     if (Conditional(cond)) 
      type.Foo(); 
     return; 
    } 
관련 문제