Autofac - Resolve Service на Enum и возвращает разные типы - PullRequest
0 голосов
/ 27 сентября 2018

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

Службы с ключами и именами

В случае с ключамиservices - если мы посмотрим на официальный пример, то увидим следующее.

builder.RegisterType<OnlineState>().Keyed<IDeviceState>(DeviceState.Online);

Мы привязываем общий интерфейс IDeviceState к конкретному классу OnlineState, и OnlineState разрешает из контейнера, если enum Device.Online

var r = container.ResolveKeyed<IDeviceState>(DeviceState.Online);

Мы связаны с методами IDeviceState при разрешении r, но теперь на мой вопрос.

Что если мои конкретные реализации, такие как OnlineState, возвращают уникальные типы, методына IDeviceState форсировать один и тот же тип возврата для всех конкретных классов.Например:

public interface IDeviceState { string GetDeviceStateInformation(); }

Теперь все мои конкретные классы вынуждены возвращать строку для GetDeviceState ();метод, в то время как разные реализации могут возвращать разные типы.

Как использовать тот же подход, но удовлетворить этот сценарий?

Пример ниже:

public class OnlineState : IDeviceState 
{   
   public string GetDeviceStateInformation() { 
     return String.empty;
     }  

}  

  public class OfflineState: IDeviceState 
{   
   public string GetDeviceStateInformation() { 
     //Im forced to use string over due to interface. 
     //But would actually like to return a int for example 
     return String.empty;
     }  
   public int GetDeviceStateInformation() { 
     //This is the actual method i want to call on the implementation class.
     //But can not due to IDeviceState
     return 5;

     }  
}  

Я хотел бы датьautofac обрабатывает разрешение правильного сервиса на основе перечисления, но не вынужден использовать методы общего интерфейса IDeviceState.

var r = container.ResolveKeyed<IDeviceState>(DeviceState.Online);
//I would like result to be different types - right now result will always 
//be string but should change depending on the service that is resolved.
var result = r.GetDeviceStateInformation();

Моя реализация на контроллере:

    [Route("api/[controller]/[action]")]
public class DeviceStateController: Controller
{
   IIndex<DeviceState, IDeviceState> _states;

    public DeviceStateController(IIndex<DeviceState, IDeviceState> states)
    {
        _states= states;
    }
    // GET api/values
    [HttpGet]
    public IActionResult GetDeviceState(DeviceState deviceEnum)
    {
       //Must Return Different Types
        return Ok(_states[deviceEnum].GetDeviceStateInformation());
    }

Ответы [ 2 ]

0 голосов
/ 27 сентября 2018

Хорошо, похоже, я понял вашу точку зрения.Проблема в том, что C # требует знать все типы во время компиляции.Таким образом, вы вынуждены немного пожертвовать сильной печатью.Посмотрите на пример ниже.Я сохранил общие классы со строгой типизацией DeviceState, однако результат GetDeviceStateInformation() передается в контроллер по ссылке object.Конечно, это не элегантный подход, у C # есть свои ограничения.

public class DeviceStateController : Controller
{
    IIndex<DeviceState, IDeviceState> _states;

    public DeviceStateController(IIndex<DeviceState, IDeviceState> states)
    {
        _states = states;
    }

    // GET api/values
    [HttpGet]
    public async Task<IActionResult> GetDeviceState(DeviceState deviceEnum)
    {
        //Must Return Different Types
        var result = await _states[deviceEnum].GetDeviceStateInformation();
        return Ok(result);
    }
}

[TestFixture]
public class DeviceStateControllerTests
{
    [Test]
    public async Task GetDeviceStateTest()
    {
        // Arrange
        var builder = new ContainerBuilder();
        builder.RegisterType<OnlineState>().Keyed<IDeviceState>(DeviceState.Online);
        builder.RegisterType<OfflineState>().Keyed<IDeviceState>(DeviceState.Offline);
        builder.RegisterType<DeviceStateController>();
        var container = builder.Build();
        var controller = container.Resolve<DeviceStateController>();

        // Act
        var stringResult = (OkObjectResult)await  controller.GetDeviceState(DeviceState.Online);
        var intResult = (OkObjectResult)await controller.GetDeviceState(DeviceState.Offline);

        //Assert
        Assert.AreEqual(stringResult.Value, "Online");
        Assert.AreEqual(intResult.Value, 404);
    }
}


public interface IDeviceState
{
    Task<object> GetDeviceStateInformation();
}

public interface IDeviceState<T> : IDeviceState
{
    new Task<T> GetDeviceStateInformation();
}

public abstract class DeviceState<T> : IDeviceState<T>
{
    public abstract Task<T> GetDeviceStateInformation();

    async Task<object> IDeviceState.GetDeviceStateInformation()
    {
        return await GetDeviceStateInformation();
    }
}

public class OnlineState : DeviceState<string>
{
    public override async Task<string> GetDeviceStateInformation()
    {
        return await Task.FromResult("Online");
    }
}

public class OfflineState : DeviceState<int>
{
    public override async Task<int> GetDeviceStateInformation()
    {
        return await Task.FromResult(404);
    }
}

public enum DeviceState
{
    Online = 1,
    Offline = 2
}

Надеюсь, это поможет.

0 голосов
/ 27 сентября 2018

Разделите интерфейс, его принцип или принципы SOLID, например, https://www.dotnetcurry.com/software-gardening/1257/interface-segregation-principle-isp-solid-principle

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...