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

C# Autofac-解析枚举上的服务并返回不同的类型,c#,dependency-injection,autofac,C#,Dependency Injection,Autofac,我知道这是可能的使用键控和命名服务,可以在这里找到的正式文档 在键控服务的情况下——如果我们看一下官方示例,就会看到这一点 builder.RegisterType<OnlineState>().Keyed<IDeviceState>(DeviceState.Online); 现在,我所有的具体类都必须为GetDeviceState()返回一个字符串;方法,而不同的实现可能返回不同的类型 如何采取相同的方法,但满足这种情况 示例如下: public class Onl

我知道这是可能的使用键控和命名服务,可以在这里找到的正式文档

在键控服务的情况下——如果我们看一下官方示例,就会看到这一点

builder.RegisterType<OnlineState>().Keyed<IDeviceState>(DeviceState.Online);
现在,我所有的具体类都必须为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处理基于枚举的正确服务的解析,但不强制使用公共接口IDEVICSTATE的方法

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();
var r=container.resolvedkeyed(DeviceState.Online);
//我希望结果是不同的类型-现在的结果将永远
//是字符串,但应根据解析的服务进行更改。
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());
    }
[路由(“api/[控制器]/[操作]”)
公共类DeviceStateController:控制器
{
美国的指数;
公共设备状态控制器(IIndex状态)
{
_国家=国家;
}
//获取api/值
[HttpGet]
公共IActionResult GetDeviceState(DeviceState deviceEnum)
{
//必须返回不同的类型
返回Ok(_states[deviceEnum].GetDeviceStateInformation());
}

分离接口,它的一个或坚实的原则,例如

好吧,看来我明白你的意思了。问题是C#要求在编译时知道所有类型。所以你不得不在某个地方牺牲一点强类型。看看下面的例子。我保留了通用强类型
设备状态
类,但是无论
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
}
公共类设备状态控制器:控制器
{
美国的指数;
公共设备状态控制器(IIndex状态)
{
_国家=国家;
}
//获取api/值
[HttpGet]
公共异步任务GetDeviceState(DeviceState deviceEnum)
{
//必须返回不同的类型
var result=await_states[deviceEnum].GetDeviceStateInformation();
返回Ok(结果);
}
}
[测试夹具]
公共类设备StateControllerTests
{
[测试]
公共异步任务GetDeviceStateTest()
{
//安排
var builder=new ContainerBuilder();
builder.RegisterType().Keyed(DeviceState.Online);
已键入builder.RegisterType()(DeviceState.Offline);
RegisterType();
var container=builder.Build();
var controller=container.Resolve();
//表演
var stringResult=(OkObjectResult)wait controller.GetDeviceState(DeviceState.Online);
var intResult=(OkObjectResult)wait controller.GetDeviceState(DeviceState.Offline);
//断言
Assert.AreEqual(stringResult.Value,“在线”);
Assert.AreEqual(intResult.Value,404);
}
}
公共界面
{
任务GetDeviceStateInformation();
}
公共界面IDeviceState:IDeviceState
{
新任务GetDeviceStateInformation();
}
公共抽象类设备状态:IDeviceState
{
公共抽象任务GetDeviceStateInformation();
异步任务IDEVICSTATE.GetDeviceStateInformation()的
{
返回等待GetDeviceStateInformation();
}
}
公共类联机状态:DeviceState
{
公共重写异步任务GetDeviceStateInformation()
{
返回等待任务。FromResult(“联机”);
}
}
公共类脱机状态:DeviceState
{
公共重写异步任务GetDeviceStateInformation()
{
返回等待任务。FromResult(404);
}
}
公共枚举设备状态
{
在线=1,
离线=2
}

希望有帮助。

-1.您应该将相关信息放在答案中。通过
Autofac
解决服务与您面临的问题无关。Autofac可以使用名称或密钥解决服务。派生类型不能更改接口方法的签名。您是否使用了通用接口
IDeviceState
?@KozhevnikovDmitry,确实是这样,问题在于当你将
IIndex\u states;
注入你的构造函数时,IDeviceState将期望已经有一个类型。就像这样
IIndex
,我不知道构造函数注入的类型,只有在我有实际的枚举要解析时才知道方法级别。只有具体的类知道它需要返回的类型。感谢您的回答,它确实对我的情况有所帮助,唯一的问题是我必须知道要从容器解析的类型,如您的示例
var state1=container.resolve();
,使用keyed的全部原因是,我被传递了一个枚举,并且基于该枚举,我需要解析一个返回类型的服务。我必须为每个可能的枚举创建一个方法,根据该服务返回类型从容器解析,这会导致每个可能的枚举的if语句或方法per enum等返回到一个函数,该函数将返回到控制器,我试图避免在控制器上为每个enum创建多个操作。它必须能够返回多个类型,即
string
int32
或强类型模型等,在我的情况下,它将仅是模型,例如
OnlineDeviceStateModel
我已经用controllerHappy to help=更新了我的原始问题)
    [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());
    }
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
}