Проблема с использованием Lazy <T>из общего абстрактного класса - PullRequest
1 голос
/ 20 мая 2010

У меня есть универсальный класс, из которого происходят все мои классы 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

    {

Итак, как я могу получить это для компиляции с использованием дисперсии (при необходимости) и обобщений, чтобы у меня был очень общий метод, который будет работать только с BaseModel и AbstractDAO<BaseModel>? Я ожидаю, что мне нужно только внести изменения в метод и, возможно, абстрактное определение класса, использование должно быть в порядке.

UPDATE: С очень полезным ответом у меня есть немного улучшенный пример, но интересная дилемма:

У меня есть это определение сейчас, и у меня нет in или out здесь T , потому что я получаю ошибки, которые противоречат, если 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 Ответ

2 голосов
/ 21 мая 2010

C # 4.0 поддержка ковариации и контравариантности при работе с делегатами и интерфейсами. Как реализована общая ковариантность и контрастность в 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.

...