在通用抽象类</t>中使用Lazy <t>的问题

时间:2010-05-20 18:03:50

标签: c#-4.0 generic-variance

我有一个我的所有DAO类派生的泛型类,定义如下。我的所有实体都有一个基类,但这不是通用的。

方法GetIdOrSave将与我定义SabaAbstractDAO的方式不同,因为我试图获得主键来实现外键关系,所以这个函数要么是获取主键或保存实体,然后获取主键。

最后一个代码片段有一个解决方案,如果我摆脱泛型部分它将如何工作,所以我认为这可以通过使用方差来解决,但我无法弄清楚如何编写一个将编译的接口

public abstract class  SabaAbstractDAO<T> :ISabaDAO<T> where T:BaseModel

    {
      ...

    public K GetIdOrSave<K>(K item, Lazy<ISabaDAO<BaseModel>> lazyitemdao) 
    where K : BaseModel
    {
         ...
    }

当我尝试编译时,我收到了这个错误:

 Argument 2: cannot convert from 'System.Lazy<ORNL.HRD.LMS.Dao.SabaCourseDAO>' to 'System.Lazy<ORNL.HRD.LMS.Dao.SabaAbstractDAO<ORNL.HRD.LMS.Models.BaseModel>>'

我试着这样称呼它:

        GetIdOrSave(input.OfferingTemplate,
            new Lazy<ISabaDAO<BaseModel>>(
                () =>
                {
                    return (ISabaDAO<BaseModel>)new SabaCourseDAO() { Dao = Dao };
                })
        );

如果我将定义改为此,则可行。

    public K GetIdOrSave<K>(K item, Lazy<SabaCourseDAO> lazyitemdao) where K : BaseModel

    {

那么,如何使用方差(如果需要)和泛型来编译它,所以我可以使用一种非常通用的方法,只适用于BaseModelAbstractDAO<BaseModel>?我希望我只需要在方法中进行更改,也许需要抽象类定义,用法应该没问题。

更新 通过一个非常有用的响应,我有一个稍微改进的例子,但一个有趣的困境:

我现在定义了这个,我在 T 上没有任何inout,因为如果out T我收到了相互矛盾的错误然后我知道它必须是contravariantly valid,如果in T然后是covariantly valid,那么我就让它保持不变,因为看起来VS2010无法理解它。

public interface ISabaDAO<T> where T:BaseModel
{
    string retrieveID(T input);
    T SaveData(T input);
}

我收到此错误,但确实已编译:

System.InvalidCastException: Unable to cast object of type 'ORNL.HRD.LMS.Dao.SabaCourseDAO' to type 'ORNL.HRD.LMS.Dao.ISabaDAO`1[ORNL.HRD.LMS.Models.BaseModel]'.

我修复了上面的两个代码段,但似乎方差不会像我希望的那样有效。

我试过这个:

public delegate K GetIdOrSave<out K>(K item, Lazy<ISabaDAO<BaseModel>> lazyitemdao)
where K : BaseModel;

但是我遇到与界面相同的问题,如果我提出out抱怨,那么我就提出了in和相反的抱怨。

如果这是合法的话,我想我可以让它工作:

public delegate K GetIdOrSave<K>(in K item, out Lazy<ISabaDAO<BaseModel>> lazyitemdao)
where K : BaseModel;

1 个答案:

答案 0 :(得分:2)

C#4.0在使用委托和接口时支持协方差和逆变。 How is Generic Covariance & Contra-variance Implemented in C# 4.0?

因此,如果你可以使用带有接口的泛型委托Lazy作为参数,那么试试这样的事情:

//covariance then you can save Giraffe as SicilianGiraffe but you cannot save Giraffe as Animal; contr-variance realization is not imposible in your case(just theoreticaly)
public interface ISabaDAO<out T> where T: BaseModel{
  int retrieveID(BaseModel);
  T SaveData(BaseModel);
}
public abstract class  SabaAbstractDAO<T> : ISabaDAO<T>{
  ...
  // in this case Lazy should be covariance delegate too
  // delegate T Lazy<out T>();
  public K GetIdOrSave<K>(K item, Lazy<ISabaDAO<BaseModel>> lazyitemdao) where K : BaseModel
  {
    ...
    return (K)itemdao.SaveData(item);// is not safe
    ...
  }
}
public class Course : BaseModel{}
public class SabaCourseDAO : SabaAbstractDAO<Course>{}

//so you can cast SabaCourseDAO to ISabaDAO<Course> and ISabaDAO<Course> to ISabaDAO<BaseModel>
// then next invoking should be valid
GetIdOrSave(new Course (), new Lazy<ISabaDAO<Course>>(() =>

                {

                    return new SabaCourseDAO() { Dao = Dao };

                })

无法检查。我没有VS2010。