Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/353.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# C语言中的匿名内部类#_C#_Java_Closures_Wicket_Anonymous Inner Class - Fatal编程技术网

C# C语言中的匿名内部类#

C# C语言中的匿名内部类#,c#,java,closures,wicket,anonymous-inner-class,C#,Java,Closures,Wicket,Anonymous Inner Class,我正在编写一个C#Wicket实现,以加深对C#和Wicket的理解。我们遇到的问题之一是Wicket大量使用匿名内部类,而C#没有匿名内部类 例如,在Wicket中,您定义了如下链接: Link link = new Link("id") { @Override void onClick() { setResponsePage(...); } }; var link = new Link("id"); link.Click += (sender, ev

我正在编写一个C#Wicket实现,以加深对C#和Wicket的理解。我们遇到的问题之一是Wicket大量使用匿名内部类,而C#没有匿名内部类

例如,在Wicket中,您定义了如下链接:

Link link = new Link("id") {
    @Override
    void onClick() {
        setResponsePage(...);
    }
};
var link = new Link("id");
link.Click += (sender, eventArgs) => setResponsePage(...);
var link = new Link("id");
link.Click = () => setResponsePage(...);
由于Link是一个抽象类,它强制实现者实现onClick方法

然而,在C#中,由于没有匿名的内部类,因此无法做到这一点。作为替代方案,您可以使用以下事件:

Link link = new Link("id") {
    @Override
    void onClick() {
        setResponsePage(...);
    }
};
var link = new Link("id");
link.Click += (sender, eventArgs) => setResponsePage(...);
var link = new Link("id");
link.Click = () => setResponsePage(...);
当然,这有几个缺点。首先,可以有多个单击处理程序,这可能并不酷。它也不会强制实现者添加单击处理程序

另一种选择可能是只具有如下所示的闭包属性:

Link link = new Link("id") {
    @Override
    void onClick() {
        setResponsePage(...);
    }
};
var link = new Link("id");
link.Click += (sender, eventArgs) => setResponsePage(...);
var link = new Link("id");
link.Click = () => setResponsePage(...);
这解决了拥有多个处理程序的问题,但仍然不会强制实现者添加处理程序


因此,我的问题是,如何在惯用C#?

中模拟类似的内容,您可以使委托成为Link类的构造函数的一部分。这样,用户将不得不添加它

public class Link 
{
    public Link(string id, Action handleStuff) 
    { 
        ...
    }

}
然后通过以下方式创建实例:

var link = new Link("id", () => do stuff);

我在@meathew的好答案之前就开始了这个过程-我会做几乎完全相同的事情,除了-除了我会从一个抽象基类开始-所以如果你不想走匿名实现的道路,你也可以自由地这样做

public abstract class LinkBase
{
    public abstract string Name { get; }
    protected abstract void OnClick(object sender, EventArgs eventArgs);
    //...
}

public class Link : LinkBase
{
    public Link(string name, Action<object, EventArgs> onClick)
    {
        _name = Name;
        _onClick = onClick;
    }

    public override string Name
    {
        get { return _name; }
    }

    protected override void OnClick(object sender, EventArgs eventArgs)
    {
        if (_onClick != null)
        {
            _onClick(sender, eventArgs);
        }
    }

    private readonly string _name;
    private readonly Action<object, EventArgs> _onClick;

}
公共抽象类链接库
{
公共抽象字符串名称{get;}
受保护的抽象void OnClick(对象发送方,EventArgs EventArgs);
//...
}
公共类链接:LinkBase
{
公共链接(字符串名称、操作onClick)
{
_名称=名称;
_onClick=onClick;
}
公共重写字符串名
{
获取{return\u name;}
}
受保护的重写void OnClick(对象发送方,EventArgs EventArgs)
{
如果(_onClick!=null)
{
_onClick(发送方、事件参数);
}
}
私有只读字符串\u名称;
私有只读操作_onClick;
}

这就是我要做的:

将链接保留为抽象类,使用工厂对其进行实例化,并将闭包/匿名方法作为工厂构建方法的参数传入。这样,您就可以将带有Link的原始设计保持为抽象类,强制通过工厂实现,并且仍然在工厂内隐藏任何具体的链接跟踪

下面是一些示例代码:

class Program
{
    static void Main(string[] args)
    {

        Link link = LinkFactory.GetLink("id", () =>
        // This would be your onClick method.
        {
                // SetResponsePage(...);
                Console.WriteLine("Clicked");
                Console.ReadLine();
        });
        link.FireOnClick();
    }
    public static class LinkFactory
    {
        private class DerivedLink : Link
        {
            internal DerivedLink(String id, Action action)
            {
                this.ID = id;
                this.OnClick = action;
            }
        }
        public static Link GetLink(String id, Action onClick)
        {
                return new DerivedLink(id, onClick);
        }
    }
    public abstract class Link
    {
        public void FireOnClick()
        {
            OnClick();
        }
        public String ID
        {
            get;
            set;
        }
        public Action OnClick
        {
            get;
            set;
        }
    }
}
编辑:实际上,这可能更接近您想要的:

Link link = new Link.Builder
{
    OnClick = () =>
    {
        // SetResponsePage(...);
    },
    OnFoo = () =>
    {
        // Foo!
    }
}.Build("id");
美妙之处在于它使用了一个init块,允许您在Link类中声明任意多个可选的操作实现

下面是相关的链接类(带有密封生成器内部类)

这与您想要的很接近,但我认为我们可以通过可选的命名参数(C#4.0特性)更进一步。让我们看看带有可选命名参数的链接声明示例:

Link link = Link.Builder.Build("id",
    OnClick: () =>
    {
        // SetResponsePage(...);
        Console.WriteLine("Click!");
    },
    OnFoo: () =>
    {
        Console.WriteLine("Foo!");
        Console.ReadLine();
    }
);
为什么这么酷?让我们看看新的链接类:

public class Link
{
    public static class Builder
    {
        private static Action DefaultAction = () => Console.WriteLine("Action not set.");
        public static Link Build(String ID, Action OnClick = null, Action OnFoo = null, Action OnBar = null)
        {
            return new Link(ID, OnClick == null ? DefaultAction : OnClick, OnFoo == null ? DefaultAction : OnFoo, OnBar == null ? DefaultAction : OnBar);
        }
    }
    public Action OnClick;
    public Action OnFoo;
    public Action OnBar;
    public String ID
    {
        get;
        set;
    }
    private Link(String ID, Action Click, Action Foo, Action Bar)
    {
        this.ID = ID;
        this.OnClick = Click;
        this.OnFoo = Foo;
        this.OnBar = Bar;
    }
}
在静态类生成器中,有一个工厂方法构建,它接受1个必需参数(ID)和3个可选参数OnClick、OnFoo和OnBar。如果未指定它们,factory方法将为它们提供默认实现

因此,在您的构造函数的Link参数参数中,您只需要实现所需的方法,否则它们将使用默认操作,而默认操作可能是空的

然而,缺点是在最后一个示例中,Link类不是抽象的。但是它不能在Link类的范围之外实例化,因为它的构造函数是私有的(强制使用Builder类来实例化Link)


您还可以直接将可选参数移动到Link的构造函数中,从而完全避免工厂的需要。

在您给出的示例中,我没有看到匿名内部类。如果希望抽象类的实现者始终实现某些方法,可以在类中创建一个抽象方法或让它实现一个接口。@tenor,定义了一个内联匿名类,该类继承自
Link
,并重写
onClick
方法。与Java不同,C#不支持从给定的用户类型派生匿名类。@Darin Dimitrov,感谢您指出这一点。我在寻找一个真正的“内部/嵌套”类。提供的示例看起来更像是从现有类派生的匿名类,至少用C#lingo来说是这样。。。这是一个内部类,因为在Java中,每个类要么是顶级类,要么是嵌套类(在另一个类中定义),要么是静态类,要么是非静态类。这是一个非静态的嵌套类,术语是内部类。这是3年前的答案,但我想在你的最终答案中提到,你可以把返回行缩短一点:返回新链接(ID,OnClick??DefaultAction,OnFoo??DefaultAction,OnBar??DefaultAction);