24

我知道它可以在 Java 中完成,因为我过去曾广泛使用过这种技术。下面将显示 Java 中的示例。(附加问题。这种技术叫什么?很难找到没有名字的例子。)

public abstract class Example {
   public abstract void doStuff();
}

public class StartHere{
   public static void main(string[] args){
      Example x = new Example(){
         public void doStuff(){
            System.out.println("Did stuff");
         }            
      };
      x.doStuff();
   }
}

现在,我的主要问题是,这也可以在 C# 中完成,如果可以,怎么做?

4

9 回答 9

21

Java 技术被称为“匿名内部类”,在 C# 中没有等价物。

于 2009-02-05T13:29:08.087 回答
17

使用 Lamba 表达式和类初始化器,您可以通过一些努力获得相同的行为。

public class Example {
    public Action DoStuff;
    public Action<int> DoStuffWithParameter;
    public Func<int> DoStuffWithReturnValue;
}

class Program {
    static void Main(string[] args) {
        var x = new Example() {
            DoStuff = () => {
                Console.WriteLine("Did Stuff");
            },
            DoStuffWithParameter = (p) => {
                Console.WriteLine("Did Stuff with parameter " + p);
            },
            DoStuffWithReturnValue = () => { return 99; }


        };

        x.DoStuff();
        x.DoStuffWithParameter(10);
        int value = x.DoStuffWithReturnValue();
        Console.WriteLine("Return value " + value);
        Console.ReadLine();
    }
}

我刚刚意识到的这个解决方案的一个问题是,如果您要在 Example 类中创建字段,则 lambda 表达式将无法访问这些字段。

但是,没有理由不能将 Example 的实例传递给 lambda 表达式,这将使它们能够访问该示例可能持有的任何公共状态。AFAIK 在功能上等同于 Java 匿名内部类。

PS如果您要否决答案,请帮我们一个忙,并就您不同意的原因添加评论:-)

于 2009-02-05T13:46:38.253 回答
10

通常,使用 Java 中的匿名内部类解决的问题可以使用 .Net 中的委托以更简洁的方式解决。您的示例有点过于简单,无法确定您的意图。如果您使用抽象类的意图是传递“行为”,请考虑只使用Action委托。

public class StartHere{
   public static void main(string[] args){
      Action doStuff = () => Console.WriteLine("Did stuff");
      executeSomething(doStuff);
   }

   public static void executeSomething(Action action)
   {
      action();
   }
}
于 2009-02-05T13:51:47.777 回答
8

这在 C# 中是做不到的;你需要声明一个新的类类型。您可以在 C# 中获得的最接近的可能是命名嵌套类:

public class StartHere{
    private class Foo : Example {
        public override void  doStuff()
        {
            Console.WriteLine("did stuff");
        }
    }
   public static void Main(string[] args){
      Example x = new Foo();
      x.doStuff();
   }
}
于 2009-02-05T13:29:56.370 回答
1

这在 C# 中不受支持,如果由我决定,也不应该如此。

Java 中内部类的激增主要是由于缺少 C# 所具有的委托或 lambda。因此,虽然这种类型的功能目前在 java 中是“您唯一的希望”,但您通常可以使用 C# 中的其他机制来实现相同的目的。在这方面,Java 感觉就像用一只手弹钢琴。

(诚​​然,我们中的很多人都非常擅长这种单手游戏;现在看来我们至少要等到 java 8 才能关闭......)

于 2009-02-05T13:36:46.513 回答
1

虽然所有好的答案,但建议的大多数解决方法都依赖于 C# 3.0

因此,为了完整起见,我将添加另一个既不使用 lambda 也不使用 Func 类型的解决方案(当然,正如 Matt Olenik 在评论中提到的那样,可以概括以下代表以同样的方式工作。)。对于像我这样可能仍在使用 C# 2.0 的人。也许不是最好的解决方案,但它确实有效。

public class Example
{
    public delegate void DoStuffDelecate();
    public DoStuffDelecate DoStuff;
    public delegate void DoStuffWithDelecate(int n);
    public DoStuffWithDelecate DoStuffWithParameter;
    public delegate int DoStuffWithReturnDelecate();
    public DoStuffWithReturnDelecate DoStuffWithReturnValue;
}

class Program
{
    static int MethodWithReturnValue()
    {
        return 99;
    }
    static void MethodForDelecate()
    {
        Console.WriteLine("Did Stuff");
    }
    static void MethodForDelecate(int n)
    {
        Console.WriteLine("Did Stuff with parameter " + n);
    }


    static void Main(string[] args)
    {
        var x = new Example();
        x.DoStuff = MethodForDelecate;
        x.DoStuffWithParameter = MethodForDelecate;
        x.DoStuffWithReturnValue = MethodWithReturnValue;

        x.DoStuff();
        x.DoStuffWithParameter(10);
        int value = x.DoStuffWithReturnValue();
        Console.WriteLine("Return value " + value);
        Console.ReadLine();
    }
}
于 2009-02-06T08:52:06.180 回答
1

由于您的类仅代表一个动作,因此您可以在您的情况下使用委托,存在一个现有委托:

public delegate void Action();

这与您的课程完全相同。

你的匿名类的声明更加清晰:

Action action = () => Console.WriteLine("Hello world");
action(); // invoke

你甚至可以使用闭包:

public void Hello(string name)
{
  Action action = () => Console.WriteLine("Hello " + name);
  action(); // will call the above lambda !
}
于 2009-02-09T10:07:15.637 回答
0

简而言之,不,您必须将其定义为单独的子类。我认为这个功能即将推出 C# 4.0 吗?

编辑:不,它不会出现 C# 4.0 我编造的。

于 2009-02-05T13:30:19.613 回答
0

您可以使用 .NET 中的 Mocking 来完成此操作。但是,没有对该功能的语言支持,我认为它将在 C# 4.0 中可用。有许多用于 Mocking 的库,包括:

于 2009-02-05T13:30:38.257 回答