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

这个错误是由泛型不隐式支持协方差引起的;也就是说,将特定的泛型参数类型视为其基本类型之一。

解决这个问题的几种方法。首先,您可以定义泛型 DebtManager 继承自的非泛型 DebtManager 基类,并将其返回。其次,您可以定义一个 DebtManager 实现的通用接口;out通过在泛型类型参数之前使用关键字,可以将泛型接口定义为协变的。

编辑:让我们回到主要需求。在编译时,您可能不知道需要使用哪种类型的对象,因此您不知道需要哪个存储库。那么,我是否可以建议您使用一个 Repository-per-database,而不是一个 Repository-per-table 架构。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 回答