如何填充接口的只读集合

How to populate a readonly collection of interfaces

我有一个任务必须完成,我需要通过以下单元测试(我无法修改)。

[Test]
public void TheJarShouldContain30SweetsWhenCreated()
{
    IJarOfSweetsCreator jarOfSweetsCreator = new JarOfSweetsCreator();
    IJarOfSweets jarOfSweets = jarOfSweetsCreator.Create();
    const int expectedNumberOfSweets = 30;
    int numberOfSweets = jarOfSweets.Count;

    Assert.AreEqual(expectedNumberOfSweets, numberOfSweets);
}

虽然说的不多,但是JarOfSweetsCreator有这段代码:

public class JarOfSweetsCreator : IJarOfSweetsCreator
{
    public IJarOfSweets Create()
    {

        //throw new NotImplementedException();
    }
}

IJarOfSweets有这个:

public interface IJarOfSweets : IReadOnlyCollection<ISweet>
{
    void Shuffle ();
    ISweet TakeSweetFromJar ();
}

我需要通过从 IJarOfSweets 创建并计数 30 来使测试通过。我不明白如何创建和计算接口的 30 个实例,如果你只能有一个,但我知道这听起来很愚蠢。

我假设它与 IJarOfSweets 界面的 IReadOnlyCollection<ISweet> 部分有关,但我不知道如何使用它。 IJarOfSweets 是像集合一样使用还是我会在此界面中创建集合?

如果是只读合集,我该如何制作 30 个?

有时,最好的办法是编写尽可能少的代码以使测试通过。这有助于您反思您的测试并确保您正在编写有用的测试。

就目前而言,您的测试需要您做一些事情。它需要你实现 JarOfSweetsCreatorCreate 方法到 return 实现 IJarOfSweets 的东西,它需要 returned 对象到 return 30当您检查它时 Count 属性.

第一步是创建一个实现接口的具体 class JarOfSweets需要做任何事情的方法是Count 属性,所以class看起来像这样:

public class JarOfSweets : IJarOfSweets {
    public void Shuffle()
    {
        throw new NotImplementedException();
    }
    public ISweet TakeSweetFromJar()
    {
        throw new NotImplementedException();
    }

    int IReadOnlyCollection<ISweet>.Count
    {
        get { return 30; }
    }

    IEnumerator<ISweet> IEnumerable<ISweet>.GetEnumerator()
    {
        throw new NotImplementedException();
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        throw new NotImplementedException();
    }
}

然后您需要将创建者更新为 return JarOfSweets class.

的新实例
public class JarOfSweetsCreator : IJarOfSweetsCreator
{
    public IJarOfSweets Create()
    {

        return new JarOfSweets();
    }
}

这是通过测试需要完成的最小值。实际上,随着您编写更多测试/编写代码以使测试通过,您可能希望对代码做更多的事情。

正如 Jon 在评论中所说,ReadOnlyCollection 只是告诉您 JarOfSweets 需要实现某些功能(获取计数 + 获取枚举器)。这并不意味着集合实际上需要 readonly。您可以使用任何内置的集合类型来实现它,也可以编写自己的集合类型。

重要的是要记住,当您知道实现接口的具体类型时,您还可以访问未在接口上定义的方法。因此,例如,在您的 JarOfSweetsCreator 中,它将需要知道 JarOfSweets 实际实现类型,而不仅仅是接口才能实例化它。这意味着 Create 方法可以调用基础集合上的其他方法,例如 Add 方法。因此,假设您有一个实现 ISweetSweet class,您最终可能会得到一个看起来更像这样的创建者:

public class JarOfSweetsCreator : IJarOfSweetsCreator
{
    public IJarOfSweets Create()
    {

        var jar = new JarOfSweets();

        for (int i = 0; i < 30; i++)
        {
            jar.Add(new Sweet());
        }

        return jar;
    }
}

然后在您的 JarOfSweets 中,它可以简单地使用 List<T> 并委托相关功能:

public class JarOfSweets : IJarOfSweets{
    public List<ISweet> _list = new List<ISweet>();

    public void Shuffle()
    {
        throw new NotImplementedException();
    }
    public ISweet TakeSweetFromJar()
    {
        throw new NotImplementedException();
    }

    public void Add(Sweet sweet)
    {
        _list.Add(sweet);
    }

    public int Count
    {
        get { return _list.Count; }
    }

    public IEnumerator<ISweet> GetEnumerator()
    {
        return _list.GetEnumerator();
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return _list.GetEnumerator();
    }
}