Dev0ps
Dev0ps

Reputation: 71

Anonymous interface implementation using C#

I have some interface:

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

And there is some method, which gets an instance of that interface for executing methods:

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

When I execute this method (start) from the main form class, I want to pass into parameters exactly the anonymous class that implements this interface to have access to use form elements:

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

But I can't do it the way I did it in Java. I get the following message:

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

So I tried to create separate class that implement this interface and already there to do what I need. But I can't to get access to use form elements from there:

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

Please tell me what to do in this case without crutches. Is it possible to use an anonymous class in C# in general? If not, what to do in this case?

Thanks in advance. Regards...

Upvotes: 1

Views: 171

Answers (2)

CodeCaster
CodeCaster

Reputation: 151586

This has nothing to do with anonymous types. You want to decouple your AnonymousIServerListener from your form. And rightfully so, because otherwise you couldn't instantiate an AnonymousIServerListener without a Form1 instance containing a TextBox rtxtOutput.

Instead you'd want, for example, an event being raised from your listener. Give your interface an event:

public interface IServerListener
{
    event EventHandler<LogEventArgs> Log;

    // ...
}

Define the EventArgs:

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

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

Then add it to your listener:

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

Finally, subscribe to your event in the class that instantiates the 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);
}

But now when Form1_Load returns, you have a dangling reference, tied by the Log event subscription. You'll never be able to unsubscribe from that, leaving your listener alive for the remainder of your application lifetime.

Upvotes: 2

Patrick Hofman
Patrick Hofman

Reputation: 156948

Why not use Actions for this...

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

And the 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; }
}

Here, ServerListener just serves as some middleware which connects the dots. It doesn't do anything itself.

Upvotes: 3

Related Questions