2012-09-28 5 views
1

다음 DBML 수정이 있습니다 (저는 Linq에서 DAL로 SQL을 사용하고 있습니다).일반 공장 패턴의 IRepository 패턴

public interface ILinqSQLObject { } 

// these are objects from SQL Server mapped into Linq to SQL 
public partial class NEWDEBT : ILinqSQLObject { } 
public partial class OLDDEBT : ILinqSQLObject { } 
public partial class VIPDEBT : ILinqSQLObject { } 

다른 Linq 개체를보다 적절하게 조작 할 수 있습니다.

방금 ​​IRepository 패턴을 구현했습니다.

public interface IDebtManager<T> 
    { 
     IQueryable<T> GetAllDebts(); 
     IQueryable T GetSpecificDebt(System.Linq.Expressions.Expression<Func<T, bool>> predicate); 
     void Insert(T debt); 
     // other methods 
    } 

public class DebtManager<T> : IDebtManager<T> where T : class, ILinqSQLObject 
    { 
     DebtContext conn = new DebtContext(); 
     protected System.Data.Linq.Table<T> table; 

     public DebtManager() 
     { 
      table = conn.GetTable<T>(); 
     } 

     public void Insert(T debt) 
     { 
      throw new NotImplementedException(); 
     } 

     public IQueryable<T> GetSpecificDebt(System.Linq.Expressions.Expression<Func<T, bool>> predicate) 
     { 
      return table.Where(predicate); 
     } 

     public IQueryable<T> GetAllDebts() 
     { 
      return table; 
     } 
    } 

그리고 완벽하게 작동합니다. 하지만 때때로 컴파일 시간에 어떤 특정 테이블을 사용할 지 모르겠습니다. 이를 위해 저는 DebtManager를위한 간단한 제네릭 팩토리를 만들려고했습니다.

public static class DebtFactoryManager 
{ 

    public static DebtManager<ILinqSQLObject> GetDebtManager(string debtType) 
    { 
     switch (debtType) 
     { 
      case "New Client": 
       return new DebtManager<NEWDEBT>(); 
      case "Old Client": 
       return new DebtManager<OLDDEBT>(); 
      case "VIP Client": 
       return new DebtManager<VIPDEBT>(); 
      default: 
       return new DebtManager<NEWDEBT>(); 
     } 

     return null; 
    } 

} 

그러나 작동하지 않습니다. 그것은 암시 적으로 DebtManager<NEWDEBT>DebtManager<ILinqSQLObject>으로 변환 할 수 없다고 말하지만 NEWDEBT가 ILinqSQLObject를 구현하면 왜 컴파일러는 그것을 인식하지 못합니까? 분명히 나는 ​​약간의 실수를하고있다. 그러나 나는 그것을 볼 수 없다.

+0

이 코드는 무엇입니까? static factory 메소드에 이름이없는 것 같습니다. –

+0

실수로 이름을 삭제했습니다. 방금 편집했습니다. 감사합니다. – AdrianoRR

답변

0

이 오류는 제네릭이 내재적으로 공분산을 지원하지 않기 때문에 발생합니다. 즉, 특정 일반 매개 변수 유형이 기본 유형 중 하나 인 것처럼 처리합니다.

몇 가지 방법이 있습니다. 먼저 일반 DebtManager가 상속하는 비 일반 DebtManager 기본 클래스를 정의한 다음이를 반환 할 수 있습니다. 둘째, DebtManager가 구현하는 일반 인터페이스를 정의 할 수 있습니다. 제네릭 형식 매개 변수 앞에 out 키워드를 사용하여 제네릭 인터페이스를 공변수로 정의 할 수 있습니다.

편집 : 기본 필요로 돌아가 보겠습니다. 컴파일 할 때 어떤 유형의 객체를 사용해야할지 알 수 없으므로 필요한 저장소가 무엇인지 모릅니다. 테이블별로 저장소 대신 데이터베이스별로 저장소를 사용하는 것이 좋습니다. DebtManager는 이미 모든 Linq to SQL 유형에 대해 일반적입니다. 그런 다음 메소드를 일반화하여 호출 간 호출에서 일반화 할 수 있습니까?

public interface IRepository<T> where T:class, ILinqSqlObject 
{ 
    IQueryable<TSpec> GetAllDebts<TSpec>() where TSpec : T; 
    IQueryable<TSpec> GetSpecificDebt<TSpec>(System.Linq.Expressions.Expression<Func<TSpec, bool>> predicate) where TSpec : T; 
    void Insert<TSpec>(TSpec debt) where TSpec:T; 
    // other methods 
} 

interface IDebtObject : ILinqSqlObject 

public interface IDebtManager:IRepository<IDebtObject> { } 

public class DebtManager:IDebtManager 
{ 
    DebtContext conn = new DebtContext(); 

    public DebtManager() 
    {    
    } 

    public void Insert<T>(T debt) where T:IDebtObject 
    { 
     throw new NotImplementedException(); 
    } 

    public IQueryable<T> GetSpecificDebt(System.Linq.Expressions.Expression<Func<T, bool>> predicate) where T:IDebtObject 
    { 
     return conn.GetTable<T>().Where(predicate); 
    } 

    public IQueryable<T> GetAllDebts<T>() where T:IDebtObject 
    { 
     return conn.GetTable<T>(); 
    } 

} 
+0

예,하지만'out'은 모든 속성, 필드 및 메소드가 읽기 전용이거나'out' 매개 변수가있는 경우에만 작동합니다. –

+0

@KeithS 신성한 .. 남자, 너 천재 야! 첫 번째 작업은 완벽하게 작동했습니다. 날 믿어, 나는이 일을 loong에 시도했다. 인터페이스가 공변 (covariant)되도록 인터페이스를 정의하는 것보다 낫다. 공변 (covariant) 인터페이스가 첫 번째 해결 방법보다 나은 상황이 있습니까? – AdrianoRR

+0

첫 번째 해결 방법은 기본적으로 컬렉션이 일반이라는 사실을 숨 깁니다. 객체가 유형에 대해 일반적이라는 것을 알아야하는 경우 (예 : 일반 유형의 하위 객체를 가져 오거나 설정하는 경우) 가장 좋은 계획은 아닙니다. 귀하의 경우, 다른 방법을 추적하거나 유형에 반영하고 일반 구성원을 조사하지 않는 한 부채 관리자가 가리키는 테이블을 알지 못합니다. – KeithS