我知道使用键控和命名服务可以实现这一点,这些服务可以在官方文档中找到。
对于 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/