Ninject 绑定通用接口
Ninject Binding Generic Interfaces
我正在尝试使用 DI 来绑定我的网络的不同实现 class。我已经能够使用 class 的 none 通用版本成功地做到这一点。我的实现如下:
class MainClass
{
public static void Main(string[] args)
{
IKernel kernel;
// Hardcode here but will be managed by build system.
bool runningInProd = false;
if (runningInProd)
{
kernel = new StandardKernel(new RealNetworkModule());
}
else
{
kernel = new StandardKernel(new FakeNetworkModule());
}
Session session = kernel.Get<Session>();
session.Authenticate();
}
public class RealNetworkModule : NinjectModule
{
public override void Load()
{
Bind(typeof(IRequestSender)).To(typeof(RealRequestSender));
}
}
public class FakeNetworkModule : NinjectModule
{
public override void Load()
{
Bind(typeof(IRequestSender)).To(typeof(FakeRequestSender));
}
}
}
Class 使用我的 IRequestSender:
public class Session
{
IRequestSender requestSender;
[Inject]
public Session(IRequestSender requestSender)
{
this.requestSender = requestSender;
}
public void Authenticate()
{
Console.WriteLine(requestSender.Send("Hello There"));
}
}
IRequestSender 接口:
public interface IRequestSender
{
string Send(string request);
}
以及两种不同的实现方式:
public class RealRequestSender: IRequestSender
{
public string Send(string request)
{
return "RealRequestSender right back at you: " + request;
}
}
public class FakeRequestSender: IRequestSender
{
public string Send(string request)
{
return "FakeRequestSender right back at you: " + request;
}
}
这非常简单而且有效;但是,我需要的是我的 IRequestSender 使用通用类型而不是字符串作为输入输出:
public interface IRequestSender<RequestT, ResponseT> where RequestT: class where ResponseT: class
{
RequestT Send(RequestT request);
}
和 impl 的:
public class FakeRequestSender<RequestT, ResponseT> : IRequestSender<RequestT, ResponseT> where RequestT : class where ResponseT : class
{
public RequestT Send(RequestT request)
{
throw new NotImplementedException();
}
}
public class RealRequestSender<RequestT, ResponseT> : IRequestSender<RequestT, ResponseT> where RequestT : class where ResponseT : class
{
public RequestT Send(RequestT request)
{
throw new NotImplementedException();
}
}
我遇到了几个解决这个问题的例子,我试图将我的实现建立在它们的基础上,但我失败了。以下是我 运行 遇到的两个问题:
1)绑定:这是主要问题。根据我在网上看到的解决方案,我的绑定看起来像这样:
public class RealNetworkModule : NinjectModule
{
public override void Load()
{
Bind(typeof(IRequestSender<>)).To(typeof(RealRequestSender<>));
}
}
VSCode 给我错误:
Program.cs(29,29): Error CS0305: Using the generic type 'IRequestSender<RequestT, ResponseT>' requires 2 type arguments (CS0305) (DI)
根据这个错误和我在网上阅读的内容,我仍然不清楚我需要在这里做什么。
2) 访问 IRequestSender:一旦我知道如何修复绑定,此问题的解决方案可能就很清楚了。在最初的实现中,我使用 [Inject] 来访问我在会话 class 中需要的 IRequestSender。但是现在在通用版本中我想我将无法做到这一点。如果我在没有 DI 的情况下使用 RequestSender,它看起来像:
RequestSender <AuthRequest, AuthResponse> requestSender = new RequestSender<AuthRequest, AuthResponse>();
或
RequestSender <UserRequest, UserResponse> requestSender = new RequestSender< UserRequest, UserResponse >();
任意数量的不同类型。
所以我不确定在这种情况下如何访问 RequestSender。
鉴于您当前的界面,您必须在注入时指定通用类型参数。假设您的请求和响应都是字符串,您的构造函数将如下所示:
public Session(IRequestSender<string, string> requestSender)
{
this.requestSender = requestSender;
}
如果您不想在 creation/injection 时指定参数,则必须稍微更改一下设计。我不能确定您提供的示例代码,但可以从您的界面中删除泛型类型参数并将它们放在方法中:
public interface IRequestSender
{
RequestT Send<RequestT, ResponseT>(RequestT request)
where RequestT: class
where ResponseT: class;
}
根据该定义,您将注入 IRequestSender
,然后在调用时指定泛型类型参数。例如,
string myResponse = requestSender.Send<string, string>("my string");
我正在尝试使用 DI 来绑定我的网络的不同实现 class。我已经能够使用 class 的 none 通用版本成功地做到这一点。我的实现如下:
class MainClass
{
public static void Main(string[] args)
{
IKernel kernel;
// Hardcode here but will be managed by build system.
bool runningInProd = false;
if (runningInProd)
{
kernel = new StandardKernel(new RealNetworkModule());
}
else
{
kernel = new StandardKernel(new FakeNetworkModule());
}
Session session = kernel.Get<Session>();
session.Authenticate();
}
public class RealNetworkModule : NinjectModule
{
public override void Load()
{
Bind(typeof(IRequestSender)).To(typeof(RealRequestSender));
}
}
public class FakeNetworkModule : NinjectModule
{
public override void Load()
{
Bind(typeof(IRequestSender)).To(typeof(FakeRequestSender));
}
}
}
Class 使用我的 IRequestSender:
public class Session
{
IRequestSender requestSender;
[Inject]
public Session(IRequestSender requestSender)
{
this.requestSender = requestSender;
}
public void Authenticate()
{
Console.WriteLine(requestSender.Send("Hello There"));
}
}
IRequestSender 接口:
public interface IRequestSender
{
string Send(string request);
}
以及两种不同的实现方式:
public class RealRequestSender: IRequestSender
{
public string Send(string request)
{
return "RealRequestSender right back at you: " + request;
}
}
public class FakeRequestSender: IRequestSender
{
public string Send(string request)
{
return "FakeRequestSender right back at you: " + request;
}
}
这非常简单而且有效;但是,我需要的是我的 IRequestSender 使用通用类型而不是字符串作为输入输出:
public interface IRequestSender<RequestT, ResponseT> where RequestT: class where ResponseT: class
{
RequestT Send(RequestT request);
}
和 impl 的:
public class FakeRequestSender<RequestT, ResponseT> : IRequestSender<RequestT, ResponseT> where RequestT : class where ResponseT : class
{
public RequestT Send(RequestT request)
{
throw new NotImplementedException();
}
}
public class RealRequestSender<RequestT, ResponseT> : IRequestSender<RequestT, ResponseT> where RequestT : class where ResponseT : class
{
public RequestT Send(RequestT request)
{
throw new NotImplementedException();
}
}
我遇到了几个解决这个问题的例子,我试图将我的实现建立在它们的基础上,但我失败了。以下是我 运行 遇到的两个问题:
1)绑定:这是主要问题。根据我在网上看到的解决方案,我的绑定看起来像这样:
public class RealNetworkModule : NinjectModule
{
public override void Load()
{
Bind(typeof(IRequestSender<>)).To(typeof(RealRequestSender<>));
}
}
VSCode 给我错误:
Program.cs(29,29): Error CS0305: Using the generic type 'IRequestSender<RequestT, ResponseT>' requires 2 type arguments (CS0305) (DI)
根据这个错误和我在网上阅读的内容,我仍然不清楚我需要在这里做什么。
2) 访问 IRequestSender:一旦我知道如何修复绑定,此问题的解决方案可能就很清楚了。在最初的实现中,我使用 [Inject] 来访问我在会话 class 中需要的 IRequestSender。但是现在在通用版本中我想我将无法做到这一点。如果我在没有 DI 的情况下使用 RequestSender,它看起来像:
RequestSender <AuthRequest, AuthResponse> requestSender = new RequestSender<AuthRequest, AuthResponse>();
或
RequestSender <UserRequest, UserResponse> requestSender = new RequestSender< UserRequest, UserResponse >();
任意数量的不同类型。
所以我不确定在这种情况下如何访问 RequestSender。
鉴于您当前的界面,您必须在注入时指定通用类型参数。假设您的请求和响应都是字符串,您的构造函数将如下所示:
public Session(IRequestSender<string, string> requestSender)
{
this.requestSender = requestSender;
}
如果您不想在 creation/injection 时指定参数,则必须稍微更改一下设计。我不能确定您提供的示例代码,但可以从您的界面中删除泛型类型参数并将它们放在方法中:
public interface IRequestSender
{
RequestT Send<RequestT, ResponseT>(RequestT request)
where RequestT: class
where ResponseT: class;
}
根据该定义,您将注入 IRequestSender
,然后在调用时指定泛型类型参数。例如,
string myResponse = requestSender.Send<string, string>("my string");