Проблема с использованием Lazy<T> из общего абстрактного класса
У меня есть универсальный класс, из которого происходят все мои классы 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>
? Я ожидаю, что мне нужно только внести изменения в метод и, возможно, абстрактное определение класса, использование должно быть в порядке.
ОБНОВЛЕНИЕ: с очень полезным ответом у меня есть немного улучшенный пример, но интересная дилемма:
У меня есть это определено сейчас, и у меня нет никаких 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 ответ
Поддержка 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.