1

次の DBML の変更があります (Linq to SQL を DAL として使用しています)。

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を実装している場合、コンパイラがそれを認識しないのはなぜですか? 明らかに私はいくつかの間違いをしていますが、私はそれを見ることができません。

4

1 に答える 1

0

このエラーは、ジェネリックが暗黙的に共分散をサポートしていないという事実によって発生します。つまり、特定のジェネリック パラメーターの型を、その基本型の 1 つであるかのように扱います。

これを回避するいくつかの方法。まず、ジェネリック 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>();
    }

}
于 2012-09-28T17:25:54.760 に答える