创建实现接口的匿名类的C#等价方法

9

最近我开始使用C#,想要找到相当于以下方法的等效方法。我不知道这被称为什么,所以我将通过代码向您展示。

在Java中,我能够创建如下接口:

public interface Event {
    public void execute();
}

并将此接口作为方法参数传递,如下所示:

public class TestEvent {
    ArrayList<Event> eventList = new ArrayList<Event>();

    public void addEvent(Event event){
        eventList.add(event);
    }

    public void simulateEvent(){
        addEvent(new Event() {
            public void execute(){
                //functionality
            }
        } );
    }

    public void processEvents(){
        for(Event event : eventList)
            eventList.execute();
    }
}

编辑:我的问题围绕着TestEvent类的simulateEvent方法,并且是否可以在C#中执行此操作。

我想知道是否有一种类似于这样的方法来实现C#中的功能(在simulateEvent方法中实例化接口),并且这实际上被称为什么。谢谢!


如果涉及到事件和事件处理,请参考C#中的事件。整个结构以不同的“C#方式”完成。在阅读过程中,您将遇到委托(即回调函数)和MulticastDelegate(即如何绑定多个事件处理程序)。 - user166390
那是一个匿名类,不,这在C#中不适用于接口。 - Tim Schmelter
https://dev59.com/z3VC5IYBdhLWcg3ww0Hr - ta.speot.is
顺便说一句:我投票关闭此问题,理由是“不是一个真正的问题”。请清楚地陈述你的意思或问题。发布的代码有许多结构,并没有隔离出任何特定的问题或问题。 - user166390
查看搜索结果 - http://stackoverflow.com/search?q=[c%23]+anonymous+interface+java,答案是否定的,但有模仿的选项。 - Alexei Levenkov
显示剩余3条评论
2个回答

6

汪...好的,请允许我做一些概括:

在Java中,您需要一种传递函数的方式。Java本身不支持作为一等公民的函数,这是实现匿名类的原因之一——打包的函数组,可以内联声明并作为接口传递给方法/其他类,然后调用这些函数。

在C#中,函数是一等公民,可以声明为DelegatesFunc<>Action<>。让我们进行一些比较(某种程度上):

一些类似于Java的结构(我的Java相当老了,所以请忍耐):

public interface IDoSomething {
    public int Return42();
    public bool AmIPrettyOrNot(string name);
    public void Foo();
} 

public void Main(String[] args) {
    DoStuff(new IDoSomething() {
        public int Return42() { return 42; }
        public bool AmIPrettyOrNot(string name) { return name == "jerkimball"; }
        public bool Foo(int x) { ... }
    });
}

public void DoStuff(IDoSomething something) { ... }

在C#中,这个(非常粗略)等价于:

public void Main(string[] args)
{
    Func<int> returns42 = () => 42;
    Func<string,bool> amIPretty = name => name == "jerkimball";
    Action<int> foo = x => {};
}

现在,正如其他人提到的那样,当处理事件时,通常在Java端看到这种模式 - 同样也在C#端:

 public class Foo 
 {
     // define the shape of our event handler
     public delegate void HandlerForBarEvent(object sender, EventArgs args);
     // declare our event
     public event HandlerForBarEvent BarEvent;

     public void CallBar()
     {
         // omitted: check for null or set a default handler
         BarEvent(this, new EventArgs());
     }
 }    

 public void Main(string[] args)
 {
      var foo = new Foo();
      // declare the handler inline using lambda syntax
      foo.BarEvent += (sender, args) => 
      {
           // do something with sender/args
      }
      foo.CallBar();
 }

请注意,我们也可以将其分配给具有相同“形状”的内容:
 public void MyHandler(object sender, EventArgs args)
 {
     // do stuff
 }
 public void Main(string[] args)
 {
      var foo = new Foo();
      // that method above is the same "shape" as HandlerForBarEvent
      foo.BarEvent += MyHandler;
      foo.CallBar();
 }

但是在Java中,它还用于定义线程的功能,如果我没记错的话(即Runnable)- 我们也可以在C#中这样做:

var thread = new Thread((Action)(() => 
     {
         // I'm the threads "run" method!
     });
thread.Start();

现在,其他的东西 - 枚举:
public void processEvents(){
    for(Event event : eventList)
        eventList.execute();
}

C#也有相同的概念,只是称呼不同:

public void processEvents()
{
    // edit: derp, 'event' is a keyword, so I'm
    // renaming this, since I won't get into why
    // you could also use @event...
    foreach(var evt in eventList)
    {
        evt.Execute();
    }
}

1
它们并不是真正的一等公民。它们更像是从F#(Action、Func、Linq(单子)、Lambda)采用的二等公民。委托并不是真正的函数,它们是用于引用函数的特殊类。 - Dustin Kingen
3
@Romoku 哦,你只是挑毛病罢了 :) - 是的,你是正确的;不要问我在单子声明期间尝试多少次击败C#编译器类型推断... - JerKimball

2

编辑:看起来你的问题是关于匿名接口实现而不是事件。你可以使用内置的Action委托类型代替你的Event接口。

然后,您可以使用lambda表达式创建Action实例。你的代码将如下所示:

public class TestEvent
{
    List<Action> eventList = new List<Action>();

    public void addEvent(Action event){
        eventList.add(event);
    }

    public void simulateEvent(){
        addEvent(() => {
        });
    }

    public void processEvents(){
        for(Action event : eventList)
            event();
    }
}

您可以使用delegate语法来替换在simulateEvent中使用() => { ... },例如delegate() { ... }
C#不支持匿名接口实现,因此如果您的接口具有多个方法,则必须在某个地方定义一个具体类。根据用法,您可以仅使此类包含委托属性,这些属性可以在创建时提供。
public class Delegates
{
    public Action Event { get; set; }
    public Func<string> GetValue { get; set; }
}

您可以像这样创建它:
var anon = new Delegates
{
    Event = () => { ... },
    GetValue = () => "Value"
}

我认为重点在于Java中可以实例化一个接口。 - ta.speot.is
@ta.speot.is,这是使用委托实例化的内容。 - Luiggi Mendoza
@ta.speot.is - 在Java中,接口实际上只是用于定义回调方法。在C#中,这些使用委托类型完成,并且事件是基于它们构建的。 - Lee
2
如果接口更加复杂,这种方式就会失效。 - ta.speot.is
@ta.speot.is - 你所说的“更详细”是什么意思?如果事件有关联数据,则可以使用不同的委托类型。如果它具有多个回调方法,则表示多个事件。 - Lee
他在simulateEvent中创建了一个匿名类(我称之为“实例化接口”),如果您需要动态构建一个具有两个方法和三个属性的接口,会发生什么?这与事件无关。 - ta.speot.is

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接