Reputation: 71
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
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
Reputation: 156948
Why not use Action
s 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