【问题标题】:Anonymous interface implementation using C#使用 C# 实现匿名接口
【发布时间】:2019-06-17 10:58:12
【问题描述】:

我有一些界面:

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

当我从主表单类执行此方法 (start) 时,我想将实现此接口的匿名类准确地传递给参数以访问使用表单元素:

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# 一般可以使用匿名类吗?如果没有,这种情况该怎么办?

提前致谢。问候...

【问题讨论】:

  • 是的,您可以创建匿名类型。不,您不能以您尝试的方式使用它们。匿名类型仅在您使用它们的代码块内有效。如果您想将它们作为参数传递,那么它们不能是匿名的。
  • @SᴇM 你没有。你可以做的是OP所说的:创建该接口的匿名实现。但无论如何。 .Net 的工作方式不同。
  • 你为什么要这样做?
  • @Fildor 所以如果你写new IServerListener() {rest here} 它将创建一个实现IServerListener 的匿名类?不知道,抱歉耽误您的时间,祝您有愉快的一天)
  • @SᴇM 不客气。这是合法的并且看起来像它实际上并没有让我发疯一次,因为一所大学广泛使用了它,而我刚刚从 .net 2.0 切换到 Java。

标签: c# interface anonymous-class


【解决方案1】:

为什么不为此使用Actions...

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】:

    这与匿名类型无关。您想将 AnonymousIServerListener 与表单分离。这样做是正确的,因为否则如果没有包含TextBox rtxtOutput 的Form1 实例,您将无法实例化AnonymousIServerListener。

    例如,您希望从侦听器中引发一个事件。给你的界面一个事件:

    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 在您的应用程序生命周期的剩余时间内保持活动状态。

    【讨论】:

    • 我的第一个想法是让 Form1 实现 IServerListener(显式)并传递 this ...我是否错过了一些非常糟糕的事情?
    • 表单是一个 UI 元素,一个监听器处理网络的东西。你不希望你的表单做太多事情。否则,如果侦听器所做的只是打印内容,那么是的,这将是表单实现的理想选择。
    • 当然,这不是“适合所有情况”的事情。我认为它真的只是为了更新状态文本。但是除了你的有效反对之外,它也可能会遇到跨线程问题......
    猜你喜欢
    • 1970-01-01
    • 2015-04-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-30
    • 2016-07-31
    • 1970-01-01
    相关资源
    最近更新 更多