#c# #generics
#c# #общие
Вопрос:
Я пытаюсь построить следующую структуру. Похоже, компилятор не согласен с тем, что ServiceTicketModel
может быть неявно преобразовано в Model<IEntity>
. Почему это так и есть ли какой-либо способ обойти это?
public abstract class ModelTest<TModel> where TModel : Model<IEntity>, new()
public abstract class Model<TEntity> where TEntity : IEntity
public class ServiceTicketModel : Model<ServiceTicket>
public class ServiceTicket : Ticket, IEntity
public class ServiceTicketModelTest : ModelTest<ServiceTicketModel>, IDisposable
Ошибка в последнем классе, и сообщение:
The type '...ServiceTicketModel' cannot be used as type parameter 'TModel' in the generic type or method 'ModelTest<TModel>'. There is no implicit reference conversion from '...ServiceTicketModel' to '...Model<IEntity>'
Ответ №1:
компилятор верен… вам нужно создать подкласс, Model<IEntity>
чтобы удовлетворить where
ограничению, которое вы добавили TModel
, но вы этого не делаете — вы создаете подкласс Model<ServiceTicket>
where ServiceTicket : IEntity
. Это не то же самое.
Если бы это было определение интерфейса или делегата, вы иногда можете использовать модификаторы отклонения ( in
/ out
), чтобы сделать его более удобным. Но вы не можете сделать это с помощью классов.
Возможно, вам потребуется использовать:
public abstract class ModelTest<TModel, TEntity>
where TModel : Model<TEntity>, new()
where TEntity : IEntity
{...}
public class ServiceTicketModelTest
: ModelTest<ServiceTicketModel, ServiceTicket>
, IDisposable
{...}
Комментарии:
1. Спасибо, это очень полезно, и я протестирую ваш пример кода. Но можете ли вы объяснить, почему это не одно и то же, или указать мне на документацию, которая объясняет это? Существует неявное преобразование между
ServiceTicket
иIEntity
, так почему бы не междуModel<ServiceTicket>
иModel<IEntity>
?2. @MartBroekkamp это проще всего объяснить на примере, подобном
List<T>
; представьте, что у вас естьList<ServiceTicket>
. Это означает, что вы ожидаете толькоServiceTicket
, верно? Теперь представьте, что вы можете неявно обрабатывать это какList<IEntity>
из-за неявного преобразования. Это означает, что вы можете иметьclass Foo : IEntity {...}
и добавлятьFoo
с помощью неявного преобразования. Значение: разрешениеList<ServiceTicket>
обращаться подобным образомList<IEntity>
позволило бы вам нарушить инвариант, который он только принимаетServiceTicket
.