c# - Autofac - 解析枚举上的服务并返回不同类型

标签 c# dependency-injection autofac

我知道使用键控和命名服务可以实现这一点,这些服务可以在官方文档中找到。

Keyed and Named Services

对于 key 服务 - 如果我们看一下官方示例,我们就会看到这一点。

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

我们将公共(public)接口(interface) IDeviceState 绑定(bind)到具体类 OnlineState,如果传递了枚举 Device.Online,则 OnlineState 将从容器中解析出来。

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

当 r 被解析时,我们受到 IDeviceState 方法的约束,但现在回答我的问题。

如果我的具体实现(例如 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 根据枚举来处理正确服务的解析,但不强制使用公共(public)接口(interface) 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();

我在 Controller 上的实现:

    [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());
    }

最佳答案

好吧,看来我明白你的意思了。问题是 C# 需要在编译时知道所有类型。所以你被迫在某个地方牺牲一点强类型。看看下面的例子。我保留了通用强类型 DeviceState 类,但是 GetDeviceStateInformation() 的结果通过 object 引用传递给 Controller ​​。这不是一个优雅的方法,当然,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
}

希望有帮助。

关于c# - Autofac - 解析枚举上的服务并返回不同类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52530494/

相关文章:

c# - EFCore 3 GroupBy+ToDictionary 引发不支持客户端 GroupBy

java - 如何从 Guice Injector 获取所有单例实例?

android - 方形 Dagger IllegalStateException : Module adapter for class MyApplicationModule could not be loaded

c# - Autofac.Hangfire 找不到已注册的类型

c# - 使用 Ninject 的 Autofac InstancePerHttpRequest

c# - Autofac:将所有 MediatR 处理程序注册为泛型类型的内部类

C# 调用返回类型为 struct* 的 c dll 函数(我没有 struct c 代码/定义)

c# - 如何为单个控件覆盖WPF MVVM中的 Material 设计并使用WPF的默认样式

C#:遇到异常。这可能是由扩展引起的

ios - Swift 将 AnyObject 转换为协议(protocol)并分配属性