【问题标题】:Equivalent of Java's anonymous class in C#?等价于 C# 中 Java 的匿名类?
【发布时间】:2022-01-04 17:21:27
【问题描述】:

我正在尝试将用 java 编写的 SDK 移植到 C#。

在这个软件中有许多“处理程序”接口和几种方法(例如:attemptSomethingHandlersuccess() 以及几种不同的故障方法)。然后在调用类中匿名实现和实例化该接口,并传递给SomethingModel 类的attemptSomething 方法。这是一个异步方法,有几个地方可能会失败或调用另一个方法(传递处理程序)。这样attemptSomethingHandler的匿名实现就可以引用调用attemptSomething的类中的私有方法。

在 C# 中,无法匿名实现接口。我可以显式地实现一个新类,但是这个实现对于这个调用类来说是唯一的,并且不会用于其他任何事情。更重要的是,我将无法访问调用类中的私有方法,而我需要并且不想公开这些方法。

基本上,我需要根据SomethingModel 类方法中发生的情况从调用类运行不同的代码。

我一直在阅读委托,但这需要传递与处理程序接口中的方法一样多的委托(据我所知)。 在 C# 中执行此操作的适当方法是什么?我觉得我错过了一个非常常见的编程策略。必须有一种简单、干净的方法来构建和解决这个问题。

【问题讨论】:

  • 也许值得用您尝试移植的 java 代码以及到目前为止的尝试来说明您的问题?
  • 你的问题不清楚,所以我不会 VTC,但你可能想看看stackoverflow.com/questions/191013/…
  • 你可以在内部类中实现接口。这样,您就可以访问调用类的私有成员。
  • 听起来你想要一个私有的嵌套类。
  • Java 中的许多匿名类型都可以用 C# 中的事件或 lambdas 代替。

标签: java c#


【解决方案1】:

使用委托:

 void AttemptSomethingAsync(Action onSuccess, Action<string> onError1, Action onError2 = null) {
     // ...
 }

 // Call it using:

 AttemptSomethingAsync(onSuccess: () => { Yes(); }, onError1: (msg) => { OhNo(msg); });

或者,使用类

 class AttemptSomethingHandler {
     Action OnSuccess;
     Action<string> OnError1;
     Action OnError2;
 }

 void AttemptSomethingAsync(AttemptSomethingHandler handler) {
     // ...
 }

 // And you call it like
 AttemptSomethingAsync(new AttemptSomethingHandler() {
       OnSuccess = () => { Yes() };
 }); 

或事件

public delegate void SuccessHandler();
public delegate void ErrorHandler(string msg);

class SomethingModel {
     public event SuccessHandler OnSuccess;
     public event ErrorHandler OnError1;

     public void AttemptSomethingAsync() {
         // ...
     }
}

// Use it like

var model = new SomethingModel();
model.OnSuccess += Yes;
model.AttemptSomethingAsync();

private void Yes() {
}

【讨论】:

  • 我来自 Java,我认为这是一个比公认的更好的答案。
【解决方案2】:

在 C# 中,我们没有像 Java 本身这样的匿名类型。您可以创建一个匿名类型,其中包含如下字段:

var myObject = new { Foo = "foo", Bar = 1, Quz = 4.2f }

但是,这些不能在其中放置方法,只能通过使用 objectdynamic 传递给方法(因为它们在编译时没有类型,它们是由编译器 AFAIK 生成的)

正如您所说,在 C# 中,我们使用委托或 lambda。

如果我正确理解你的泡菜,你可以像这样实现一个嵌套的私有类:

interface IMyInterface
{
    void Foo();
}

class MyClass
{
    public void Bar()
    {
        var obj = new MyInterface();
        obj.Foo();
    }

    private class MyInterface : IMyInterface
    {
        public void Foo()
        {
            // stuff
        }
    }
}

现在MyClass 可以创建一个实现IMyInterfaceMyInterface 实例。正如评论者所提到的,MyInterface 可以访问 MyClass 的成员(尽管您当然想尝试并坚持使用这两种类型的可公开访问的成员)。

这封装了“匿名”类(此处使用 Java 术语以使其更简单),也意味着您可以将MyInterface 作为IMyInterface 返回,而软件的其余部分也不会更明智。这实际上是一些抽象工厂模式的工作原理。


基本上,我需要根据 SomethingModel 类方法中发生的情况从调用类运行不同的代码。

这有重耦合的味道。天哪!

在我看来,您的特定问题可以使用重构。在 C# 中,您可以使用事件来解决这个问题(注意:可以,不应该)。只需为方法的每个“分支”点设置一个事件。但是我必须说,这确实使您的解决方案更难以设想和维护。

但是,我建议您以一种不需要如此重耦合的方式来构建您的解决方案。

您也可以尝试使用 Pipeline 模型,但我不确定如何自己实现。我知道 jetty(或者是 Netty?JBOSS 的 Java 的 NIO)肯定使用了类似的模型。

您可能会发现,为了测试您的类的预期功能而放弃一些单元测试将更容易构建您的解决方案 (TDD)。

【讨论】:

  • “虽然你肯定想尝试并坚持使用这两种类型的可公开访问的成员”为什么?
  • 耦合。虽然我认为在这种情况下它是没有实际意义的,因为它是一个私有嵌套类。如果可以避免的话,我个人会尽量避免使用嵌套类中的私有方法——这不是 private 的用途。我可能应该提到我的意思是避免在嵌套类中使用私有方法,而不是避免使用内部/受保护的方法。另外,我假设如果您将接口实现为嵌套类,您不希望从父类中触及嵌套类的私有方法。
  • 感谢您的回复。根据您使用嵌套私有类的示例: IMyInterface 可能需要在不同的类中以不同的方式实现。所以 Foo() 可能需要访问 MyClass 的实例和传递给 Bar() 的参数。但在其他地方,它可能需要其他参数等。听起来你是对的,我的解决方案需要进行重大重构。认为我可以保持与 java 实现相同的结构可能是愚蠢的 :) 听起来我可以使用事件。在某些情况下,这些事件必须由使用 SDK 的人来实现,这可能吗?
  • 如果你指的是Java SDK,恐怕interop超出了我的能力范围。
  • 因为(几乎)从来没有一个很好的理由来使用匿名课程。 @nicolas他们是XY问题的一个例子。匿名类唯一可接受的用途是在生成的代码中,即使这样,更好的主意是使用生成的类名。在 Java 中甚至使用匿名类的最大原因是因为没有 lambda 类型
【解决方案3】:

您可以使用嵌套类来模拟匿名类,但为了以与 Java 相同的方式使用嵌套类,您需要传递对外部类的引用。在 Java 中,所有嵌套类和匿名类默认都有这个,只有静态类没有。

interface IMyInterface
{
    void Foo();
}

class MyClass
{
    public void Bar()
    {
        IMyInterface obj = new AnonymousAnalog(this);
        obj.Foo();
    }

    private class AnonymousAnalog : IMyInterface
    {
        public void Foo(MyClass outerThis)
        {
            outerThis.privateFieldOnOuter;
            outerThis.PrivateMethodOnOuter();
        }
    }

    ...
}

【讨论】:

  • 嵌套类可以使用OuterClass.this访问创建它们的父类的实例。
  • @Samah 你是什么意思?你在谈论Java吗?如果是这样,你是对的。但是这个人正在解释 C#。在 C# 中,您不能使用 OuterClass.this
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-05
  • 1970-01-01
  • 1970-01-01
  • 2010-10-15
  • 2018-02-10
相关资源
最近更新 更多