Ninject绑定通用接口

问题描述 投票:0回答:1

我正在尝试使用DI来绑定我的网络类的不同实现。我已经能够成功地使用该类的非泛型版本。我的实现如下:

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

使用我的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使用Generic类型而不是字符串作为输入输出:

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]来访问我在Sessions类中需要的IRequestSender。但是现在在通用版本中,我想我将无法做到这一点。如果我在没有DI的情况下使用RequestSender,它看起来像:

RequestSender <AuthRequest, AuthResponse> requestSender = new RequestSender<AuthRequest, AuthResponse>();

要么

RequestSender <UserRequest, UserResponse> requestSender = new RequestSender< UserRequest, UserResponse >();

适用于任何数量的不同类型。

所以我不确定如何在这种情况下访问RequestSender。

c# ninject
1个回答
1
投票

给定当前接口,您必须在注入时指定泛型类型参数。假设您的请求和响应都是字符串,您的构造函数将如下所示:

public Session(IRequestSender<string, string> requestSender)
{
    this.requestSender = requestSender;
}

如果您不想在创建/注入时指定参数,则必须稍微更改设计。我不能肯定地说你提供的示例代码,但是可以从界面中删除泛型类型args并将它们放在方法上:

public interface IRequestSender
{
    RequestT Send<RequestT, ResponseT>(RequestT request)
        where RequestT: class
        where ResponseT: class;
}

根据该定义,您将注入IRequestSender,然后在调用时指定泛型类型参数。例如,

string myResponse = requestSender.Send<string, string>("my string");
© www.soinside.com 2019 - 2024. All rights reserved.