将谓词作为参数传递(C#)

3
最近我做了一份来自一家公司的评估,其中有一个案例,他们想将谓词设置为方法的输入参数。由于我对此几乎没有经验,所以我一直在自己进行研究。代码看起来像这样:
using System;

public interface IBird
{
    Egg Lay();
}

public class Chicken : IBird
{
    public Chicken()
    {
    }

    public void EggLay()
    {
    }

    public Egg Lay()
    {
        return new Egg();
    }
}

public class Egg
{
    public Egg(Func<IBird> createBird)
    {
        throw new NotImplementedException("Waiting to be implemented.");
    }

    public IBird Hatch()
    {
        throw new NotImplementedException("Waiting to be implemented.");
    }
}

public class Program
{
    public static void Main(string[] args)
    {
//      var chicken1 = new Chicken();
//      var egg = chicken1.Lay();
//      var childChicken = egg.Hatch();
    }
}

我的问题是Egg函数期望什么,为什么?
我已经看过this answerthis answerthis answer,但还是没有意义。现在这个问题已经变成了学术性的,但我真的想要理解。

2
你链接的答案都很好,到底是什么让你感到困惑呢? - BradleyDotNET
4
顺便提一下,Func<IBird>不是一个谓词。谓词应该类似于Func<IBird, bool>或者Predicate<IBird>这样的形式。 - Jon Skeet
2
你对委托(delegates)的了解有多少?此刻很难回答这个问题,因为我们不知道该从何处开始解释。 - Jon Skeet
老实说,我对委托不太理解,所以很多解释都有点难以理解。 - Memnoch The Coder
1
一个委托本质上是一个函数指针。 - Igor
显示剩余2条评论
3个回答

9

public Egg(Func<IBird> createBird) 不是一个函数,而是 Egg 类的 构造函数。由于 Egg 类必须孵化鸟类,因此它需要创建鸟类。 Func<IBird> 是一个委托,即表示对方法的引用的值。在这种特殊情况下,它表示一个 工厂方法。谓词是返回布尔值的方法或委托。通过这个参数,您可以传递任何创建 IBird 的方法。由于 IBird 接口没有指定鸟类的显式实现,因此您可以使用不同的方法初始化 Egg,从而创建不同类型的鸟类。一些需要构造函数参数,一些则不需要。

您可以像这样实现 Egg

public class Egg
{
    private readonly Func<IBird> _createBird;

    public Egg(Func<IBird> createBird)
    {
        _createBird = createBird; // No "()". createBird is not called, just assigned.
    }

    public IBird Hatch()
    {
        return _createBird(); // Here createBird is called, therefore the "()".
    }
}

现在,Hatch方法可以通过_createBird委托的中间层创建鸟类,而不需要知道如何创建或创建哪种类型的鸟类。
你该如何创建一个蛋呢?首先,你需要一些鸟类的实现,例如:
public class BlackBird : IBird
{
    ... your implementation goes here
}

然后你需要一个创建并返回 IBird 的方法。例如:

IBird CreateBlackBird()
{
    return new BlackBird();
}

您可以使用以下命令创建一个egg:
var egg = new Egg(CreateBlackBird); // No "()". CreateBlackBird is not called but referenced.
IBird newBird = egg.Hatch();

确保不带参数列表传递该方法,即不带括号,因为此时您不想调用CreateBlackBird方法,而是要将其传递给构造函数,在那里它将存储在私有字段_createBird中以供稍后使用。
Lambda表达式会即时创建一个匿名委托:
var egg = new Egg(() => new BlackBird());

() => new BlackBird()是一个Lambda表达式。它等同于CreateBlackBird方法。返回类型没有指定,从Egg构造函数的参数类型推断出来。它没有名称。只剩下了方法头中的参数括号。=>替换了return关键字。

在实现了一个带有颜色作为构造函数参数的额外鸟类之后,您可以编写:

var egg = new Egg(() => new ColoredBird(Color.Blue));

另请参阅:


0

谢谢这个例子。 您可以通过修改Egg类来实现单例模式,以便鸟只能孵化一次:

    public class Egg
{
    private readonly Func<IBird> _createBird;
    private IBird _Bird = null;

    public Egg(Func<IBird> createBird)
    {
        _createBird = createBird;
    }

    public IBird Hatch()
    {
        if (_Bird == null)
        {
            _Bird = _createBird();
        }

        return _Bird;
    }
}

0
你可以通过修改Egg类来实现单例模式,使得鸟只能孵化一次。
public interface IBird
    {
        Egg Lay();
    }
    public class Egg
    {
        private readonly Func<IBird> _createBird;
        private bool _hatched;

        public Egg(Func<IBird> createBird)
        {
            _createBird = createBird;
        }

        public IBird Hatch()
        {
            if (_hatched)
                Console.WriteLine("Egg are already hatched");
            _hatched = true;
            Console.WriteLine("Egg are hatched now;");
            Console.ReadKey();
            return _createBird();
        }
    }

    public class Chicken : IBird
    {
        public Egg Lay()
        {
            var egg = new Egg(() => new Chicken());
            return egg;
        }
    }

    public class Program
    {
        public static void Main(string[] args)
        {
            var chicken1 = new Chicken();
            var egg = chicken1.Lay();
            var childChicken = egg.Hatch();
        }
    }

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