Реализация анонимного интерфейса с использованием C # - PullRequest
0 голосов
/ 17 июня 2019

У меня есть интерфейс:

interface IServerListener
{
    void onServerStarted();
    void onSessionStarted();
    void onSessionCompleted(List<string> data);
}

И есть метод, который получает экземпляр этого интерфейса для выполнения методов:

public void start(IServerListener listener)
{
    IPEndPoint hostPoint = new IPEndPoint(IPAddress.Parse(getLocalHost()), PORT);
    serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    serverSocket.Bind(hostPoint);
    serverSocket.Listen(5);

    listener.onServerStarted(); //Calling

    while(true)...
}

Когда я выполняю этот метод (начало) из основного класса формы, я хочу передать в параметры именно анонимный класс, который реализует этот интерфейс, чтобы иметь доступ к использованию элементов формы:

private void Form1_Load(object sender, EventArgs e)
{
    server = new Server();
    server.start(new IServerListener()
    {
        void onServerStarted()
        {
            rtxtOutput.AppendText("Started... ");
        }

        void onSessionCompleted(List<string> data)
        {
            rtxtOutput.AppendText("Session completed: " + String.Join(", ", data));
        }

        void onSessionStarted()
        {
            rtxtOutput.AppendText("New session started... ");
        }
    });
}

Но я не могу сделать это так, как я это делал в Java . Я получаю следующее сообщение:

Cannot create an instance of the abstract class or interface 'IServerListener'

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

private class AnonymousIServerListener : IServerListener
{
    public void onServerStarted()
    {
        rtxtOutput.AppendText("Started... ");
        //The name 'rtxtOutput' does not exist in the current context
    }

    public void onSessionCompleted(List<string> data)
    {
        rtxtOutput.AppendText("Session completed: " + String.Join(", ", data));
        //The name 'rtxtOutput' does not exist in the current context
    }

    public void onSessionStarted()
    {
        rtxtOutput.AppendText("New session started... ");
        //The name 'rtxtOutput' does not exist in the current context
    }
}

Скажите, пожалуйста, что делать в этом случае без костылей. Можно ли вообще использовать анонимный класс в C # ? Если нет, что делать в этом случае?

Заранее спасибо. С уважением ...

Ответы [ 2 ]

3 голосов
/ 17 июня 2019

Почему бы не использовать Action s для этого ...

private void Form1_Load(object sender, EventArgs e)
{
    server = new Server();
    server.start(new ServerListener()
        { OnServerStarted = () => rtxtOutput.AppendText("Started... ")
        , OnSessionCompleted = data =>
            {
                rtxtOutput.AppendText("Session completed: " + String.Join(", ", data));
            }
        , OnSessionStarted = () => rtxtOutput.AppendText("New session started... ")
        )
    );
}

А ServerListener:

public class ServerListener : IServerListener
{
    void IServerListener.onServerStarted() => OnServerStarted?.Invoke();
    void IServerListener.onSessionStarted() => OnSessionStarted?.Invoke();
    void IServerListener.onSessionCompleted(List<string> data) => OnSessionCompleted?.Invoke(data);

    public Action OnServerStarted { get; set; }

    public Action<List<string>> OnSessionCompleted { get; set; }

    public Action OnSessionStarted { get; set; }
}

Здесь ServerListener просто служит некоторым промежуточным программным обеспечением, которое соединяет точки. Сам ничего не делает.

2 голосов
/ 17 июня 2019

Это не имеет ничего общего с анонимными типами.Вы хотите отделить вашу AnonymousIServerListener от вашей формы.И это правильно, потому что в противном случае вы не могли бы создать экземпляр AnonymousIServerListener без Form1 экземпляра, содержащего TextBox rtxtOutput.

Вместо этого вы бы хотели, например, событие, вызываемое вашим слушателем.Дайте вашему интерфейсу событие:

public interface IServerListener
{
    event EventHandler<LogEventArgs> Log;

    // ...
}

Определите EventArgs:

public class LogEventArgs : EventArgs
{
    public string LogText { get; }

    public LogEventArgs(string logText)
    {
        LogText = logText;
    }
}

Затем добавьте его в ваш слушатель:

public class AnonymousIServerListener : IServerListener
{
    public event EventHandler<LogEventArgs> Log = delegate { };

    public void OnServerStarted()
    {
        Log.Invoke(new LogEventArgs("Started... "));
    }

    public void OnSessionCompleted(List<string> data)
    {
        Log.Invoke(new LogEventArgs("Session completed: " + String.Join(", ", data)));
    }

    public void OnSessionStarted()
    {
        Log.Invoke(new LogEventArgs("New session started... "));
    }
}

Наконец, подпишитесь на ваше событиев классе, который создает экземпляр AnonymousIServerListener:

private void Form1_Load(object sender, EventArgs e)
{
    server = new Server();

    IServerListener listener = new AnonymousIServerListener();

    listener.Log += (e) => rtxtOutput.AppendText(e.LogText);

    server.start(listener);
}

Но теперь, когда возвращается Form1_Load, у вас есть свисающая ссылка, связанная подпиской на событие журнала.Вы никогда не сможете отписаться от этого, оставив свой listener живым на оставшуюся часть жизни вашего приложения.

...