Фабрика вернет реализацию Generic

Я пытаюсь вернуть реализацию универсального абстрактного класса с использованием фабрики, чтобы вызывающей стороне не нужно было знать, что вернул конкретный тип. Но не удалось.

Классы сущностей

public class Car:IMoveable    { }
public interface IMoveable    { }

Классы обслуживания

public abstract class Service<TEntity>
{
   public abstract void PerformService(TEntity t);
}

public class VehicleService : Service<IMoveable>
{
     public override void PerformService(IMoveable t) {     }
}

public class DefaultService : Service<object>
{
     public override void PerformService(object t){  }
}

Фабрика:

public static class ServiceFactory
{
   public static Service<TEntity> CreateService<TEntity>(TEntity entity) where TEntity : class
   {
      if (typeof(IMoveable).IsAssignableFrom(typeof(TEntity)))
      {
          // run time error here as returns null
          return  new VehicleService() as Service<TEntity>;
          //compiler error
          return (Service<TEntity>) new VehicleService();
      }
      else
      {
         return new DefaultService() as Service<TEntity>;
      }
   }
}

Код вызова

static void Main(string[] args)
{
   var car = new Car();
   var service = ServiceFactory.CreateService(car);
}

Проблема в том, что служба после createService всегда имеет значение null.

Я подозреваю, что проблема в том, что TEntity передается как Car, тогда как VehicleService реализуется как IMovebale. Но никак не могу понять, как это сделать, и возможно ли это вообще?

Заранее спасибо.

В вашем примере TEntity - это Car. Итак, вы пытаетесь преобразовать объект типа Service<IMoveable> в тип Service<Car> ( Service<TEntity> ), но это невозможно, поскольку они не являются контравариантными. Вы можете пометить параметр типа ключевым словом in, как описано здесь: docs.microsoft.com/en-us/dotnet/standard/generics/…

SergeyIL 22.05.2019 12:24
3 метода стилизации элементов HTML
3 метода стилизации элементов HTML
Когда дело доходит до применения какого-либо стиля к нашему HTML, существует три подхода: встроенный, внутренний и внешний. Предпочтительным обычно...
Формы c голосовым вводом в React с помощью Speechly
Формы c голосовым вводом в React с помощью Speechly
Пытались ли вы когда-нибудь заполнить веб-форму в области электронной коммерции, которая требует много кликов и выбора? Вас попросят заполнить дату,...
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Будучи разработчиком веб-приложений, легко впасть в заблуждение, считая, что приложение без JavaScript не имеет права на жизнь. Нам становится удобно...
Flatpickr: простой модуль календаря для вашего приложения на React
Flatpickr: простой модуль календаря для вашего приложения на React
Если вы ищете пакет для быстрой интеграции календаря с выбором даты в ваше приложения, то библиотека Flatpickr отлично справится с этой задачей....
В чем разница между Promise и Observable?
В чем разница между Promise и Observable?
Разберитесь в этом вопросе, и вы значительно повысите уровень своей компетенции.
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Клиент для URL-адресов, cURL, позволяет взаимодействовать с множеством различных серверов по множеству различных протоколов с синтаксисом URL.
1
1
64
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вам нужно пометить TEntity общий тип Service как контравариантный с помощью ключевого слова in и использовать базовый интерфейс вместо базового абстрактного класса, тогда будет работать приведение к универсальному базовому типу:

public interface Service<in TEntity>
{
    void PerformService(TEntity t);
}

Другие вопросы по теме