2012-10-29 2 views
6

샘플 프로그램은 :제네릭 동작을 설명하고 해결 방법이 있습니까? 아래

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

namespace GenericsTest 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      IRetrievable<int, User> repo = new FakeRepository(); 

      Console.WriteLine(repo.Retrieve(35)); 
     } 
    } 

    class User 
    { 
     public int Id { get; set; } 
     public string Name { get; set; } 
    } 

    class FakeRepository : BaseRepository<User>, ICreatable<User>, IDeletable<User>, IRetrievable<int, User> 
    { 
     // why do I have to implement this here, instead of letting the 
     // TKey generics implementation in the baseclass handle it? 
     //public User Retrieve(int input) 
     //{ 
     // throw new NotImplementedException(); 
     //} 
    } 

    class BaseRepository<TPoco> where TPoco : class,new() 
    { 
     public virtual TPoco Create() 
     { 
      return new TPoco(); 
     } 

     public virtual bool Delete(TPoco item) 
     { 
      return true; 
     } 

     public virtual TPoco Retrieve<TKey>(TKey input) 
     { 
      return null; 
     } 
    } 

    interface ICreatable<TPoco> { TPoco Create(); } 
    interface IDeletable<TPoco> { bool Delete(TPoco item); } 
    interface IRetrievable<TKey, TPoco> { TPoco Retrieve(TKey input); } 
} 

이 샘플 프로그램은 내 실제 프로그램이 사용하는 인터페이스를 나타내고, (FakeRepository에서 주석) 나는 데 문제를 보여줍니다. 이 메서드 호출은 일반적으로 기본 클래스 (실제 예제에서는 95 %를 처리 할 수 ​​있음)에서 처리하여 TKey의 형식을 명시 적으로 지정하여 자식 클래스에서 재정의 할 수 있도록하고 싶습니다. IRetrievable에 어떤 매개 변수 제약 조건을 사용하는지는 중요하지 않지만 기본 클래스로 전달되는 메서드 호출은 결코 얻을 수 없습니다.

또한 이런 종류의 동작을 구현하고 궁극적으로 내가 원하는 결과를 얻는 다른 방법을 볼 수 있다면 매우 흥미로울 것입니다.

생각하십니까?

답변

3

을 컴파일되지 않습니다.

public interface IBar 
{ 
    void Foo(int i); 
} 

public class Bar : IBar 
{ 
    public void Foo<T>(T i) 
    { 
    } 
} 

이 메서드는 단순히 동일한 서명이 없습니다. 예, someBar.Foo(5)으로 전화를 걸어 Tint으로 해결할 수 있지만 실제로 FooBar은 여전히 ​​int을 매개 변수로 사용하는 메서드와 동일한 서명을 갖고 있지 않습니다.

형식에 제네릭이 아닌 일반 메서드를 모두 포함하면이 문제를 더욱 효과적으로 나타낼 수 있습니다. 이 모호성 관련 오류가 발생하지 않습니다

public class Bar : IBar 
{ 
    public void Foo(int i) 
    { 

    } 
    public void Foo<T>(T i) 
    { 
    } 
} 

실제로 문제를 해결하기위한, 당신이 할 수 있습니다 :

class FakeRepository : BaseRepository<User>, ICreatable<User>, IDeletable<User>, IRetrievable<int, User> 
{ 
    public User Retrieve(int input) 
    { 
     return Retrieve<int>(input); 
    } 
} 

FakeRespository가 가지고있는 의미합니다 모두 일반 및 제네릭이 아닌 버전은 Retrieve이지만 결국 모든 호출은 여전히 ​​일반 버전으로 전달됩니다.

1

컴파일러는 BaseRepository에 있으며 IRetreivable이 관련된 방법이 없습니다 무엇 TKey 모르고있다 (일반적인 방법은 제네릭이 아닌 것과 동일한 서명이없는 점에 유의).

나는 당신이 인터페이스 상속을하는 기본 클래스와이 라인을 따라 뭔가 더 원하는 생각하고, 또한 TKey 지정 : 그 코드가 같은 이유로이 간단한 예를 들어 컴파일되지 않습니다

class FakeRepository : BaseRepository<int, User> 
{ 
} 

class BaseRepository<TKey, TPoco> : ICreatable<TPoco>, IDeletable<TPoco>, IRetrievable<TKey, TPoco> where TPoco : class,new() 
{ 
    public virtual TPoco Create() 
    { 
     return new TPoco(); 
    } 

    public virtual bool Delete(TPoco item) 
    { 
     return true; 
    } 

    public virtual TPoco Retrieve<TKey>(TKey input) 
    { 
     return null; 
    } 
} 
+0

불행히도 원래의 예제에 포함시키지 않았지만, FakeRepository에는 여러 개의 IRetrievable 인터페이스가 정의되어있을 수 있습니다. 모든 인터페이스는 동일한 TPoco이지만 다른 TKey가 있습니다. –

관련 문제