Родовые интерфейсы Ninject Binding - PullRequest
0 голосов
/ 08 марта 2019

Я пытаюсь использовать 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 использовал универсальные типы, а не строку для ввода:

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

И подсчет:

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], чтобы получить доступ к IRequestSender, который мне нужен в моем классе Sessions. Однако теперь в общей версии, я думаю, я не смогу сделать это. Если бы я использовал RequestSender без DI, он бы выглядел так:

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

или

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

для любого количества разных типов.

Так что я не уверен, как получить доступ к RequestSender в этом сценарии.

1 Ответ

1 голос
/ 08 марта 2019

Учитывая ваш текущий интерфейс, вы должны будете указать аргументы универсального типа при введении.Предполагая, что ваш запрос и ответ являются строками, ваш конструктор будет выглядеть так:

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

Если вы не хотите указывать аргументы во время создания / внедрения, вам придется немного изменить дизайн,Я не могу сказать наверняка с примером кода, который вы предоставили, но может быть возможно удалить аргументы универсального типа из вашего интерфейса и вместо этого поместить их в метод:

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

С этим определением вы'введите IRequestSender, а затем укажите параметры универсального типа при вызове.Например,

string myResponse = requestSender.Send<string, string>("my string");
...