简体   繁体   English

我应该定义自定义枚举器还是使用内置枚举器?

[英]Should I define custom enumerator or use built-in one?

I've been given some code from a customer that looks like this: 我收到了一些客户的代码,如下所示:

public class Thing
{
    // custom functionality for Thing...
}

public class Things : IEnumerable
{
    Thing[] things;
    internal int Count { get { return things.Length; } }

    public Thing this[int i] { get { return this.things[i]; } }

    public IEnumerator GetEnumerator() { return new ThingEnumerator(this); }

    // custom functionality for Things...
}

public class ThingEnumerator : IEnumerator
{
    int i;
    readonly int count;
    Things container;

    public ThingEnumerator(Things container)
    {
        i = -1;
        count = container.Count;
        this.container = container;
    }

    public object Current { get { return this.container[i]; } }
    public bool MoveNext() { return ++i < count; }
    public void Reset() { i = -1; }
}

What I'm wondering is whether it would have been better to have gotten rid of the ThingEnumerator class and replaced the Things.GetEnumerator call with an implementation that simply delegated to the array 's GetEnumerator ? 我想知道的是,摆脱ThingEnumerator类并用一个简单地委托给arrayGetEnumerator的实现替换Things.GetEnumerator调用是否会更好? Like so: 像这样:

public IEnumerator GetEnumerator() { return things.GetEnumerator(); }

Are there any advantages to keeping the code as is? 保持代码原样有什么好处吗? (Another thing I've noticed is that the existing code could be improved by replacing IEnumerator with IEnumerator<Thing> .) (我注意到的另一件事是可以通过用IEnumerator<Thing>替换IEnumerator来改进现有代码。)

With generics, there is really little value in implementing IEnumerable and IEnumerator yourself. 使用泛型,自己实现IEnumerableIEnumerator几乎没什么价值。

Removing these are replacing the class with a generic collection means you have far less code to maintain and has the advantage of using code that is known to work. 删除这些正在用通用集合替换类意味着您需要维护的代码要少得多,并且具有使用已知可用的代码的优势。

In the general case, there can sometimes be a reason to implement your own enumerator. 在一般情况下,有时可能有理由实现自己的枚举器。 You might want some functionality that the built-in one doesn't offer - some validation, logging, raising OnAccess-type events somewhere, perhaps some logic to lock items and release them afterwards for concurrent access (I've seen code that does that last one; it's odd and I wouldn't recommend it). 您可能需要一些内置的功能不提供的功能 - 一些验证,日志记录,在某处引发OnAccess类型的事件,可能是一些逻辑来锁定项目并在之后释放它们以进行并发访问(我已经看到了那样做的代码)最后一个;它很奇怪,我不推荐它)。

Having said that, I can't see anything like that in the example you've posted, so it doesn't seem to be adding any value beyond what IEnumerable provides. 话虽如此,我在你发布的例子中看不到类似的东西,所以它似乎没有增加IEnumerable提供的任何值。 As a rule, if there's built-in code that does what you want, use it. 通常,如果有内置代码可以执行您想要的操作,请使用它。 All you'll achieve by rolling your own is to create more code to maintain. 通过自己动手来实现的就是创建更多代码来维护。

The code you have looks like code that was written for .NET 1.0/1.1, before .NET generics were available - at that time, there was value in implementing your own collection class (generally derived from System.Collections.CollectionBase ) so that the indexer property could be typed to the runtime type of the collection. 您拥有的代码看起来像是在.NET泛型可用之前为.NET 1.0 / 1.1编写的代码 - 那时,实现您自己的集合类(通常派生自System.Collections.CollectionBase )是有价值的,这样就可以了可以将indexer属性键入到集合的运行时类型中。 However, unless you were using value types and boxing/unboxing was the performance limitant, I would have inherited from CollectionBase and there would be no need to redefine GetEnumerator() or Count . 但是,除非您使用值类型并且装箱/取消装箱是性能限制,否则我将继承自CollectionBase并且不需要重新定义GetEnumerator()Count

However, now, I would recommend one of these two approaches: 但是,现在,我建议采用以下两种方法之一:

  1. If you need the custom collection to have some custom functionality, then derive the collection from System.Collections.ObjectModel.Collection<Thing> - it provides all the necessary hooks for you to control insertion, replacement and deletion of items in the collection. 如果您需要自定义集合具有一些自定义功能,则从System.Collections.ObjectModel.Collection<Thing>派生集合 - 它提供了所有必要的挂钩,以便您控制集合中项目的插入,替换和删除。

  2. If you actually only need something that needs to be enumerated, I would return a standard IList<Thing> backed by a List<Thing> . 如果你实际上只需要枚举的东西,我会返回一个由List<Thing>支持的标准IList<Thing> List<Thing>

Unless you are doing something truly custom (such as some sort of validation) in the custom enumerator, there really isn't any reason to do this no. 除非您在自定义枚举器中执行真正自定义(例如某种验证)的操作,否则没有任何理由不这样做。

Generally, go with what is available in the standard libraries unless there is definite reason not to. 一般情况下,除非有明确的理由,否则请使用标准库中的可用内容。 They are likely better tested and have more time spent on them, as individual units of code, then you can afford to spend, and why recreate the wheel? 它们可能经过更好的测试,并且有更多的时间花在它们上,作为单独的代码单元,那么你可以负担得起,以及为什么重新创建轮子?

In cases like this, the code already exists but it may still be better to replace the code if you have time to test very well. 在这种情况下,代码已经存在,但如果你有时间进行测试,替换代码可能仍然会更好。 (It's a no-brainer if there is decent unit test coverage.) (如果有适当的单元测试覆盖率,这是明智的。)

You'll be reducing your maintenance overhead, removing a potential source of obscure bugs and leaving the code cleaner than you found it. 您将减少维护开销,消除潜在的模糊错误源并使代码比您发现的更干净。 Uncle Bob would be proud. 鲍勃叔叔会感到自豪。

An array enumerator does pretty much the same as your custom enumerator, so yes, you can just as well return the array's enumerator directly. 数组枚举器与自定义枚举器几乎完全相同,所以是的,您也可以直接返回数组的枚举器。
In this case, I would recommend you do it, because array enumerators also perform more error checking and, as you stated, it's just simpler. 在这种情况下,我建议你这样做,因为数组枚举器也执行更多的错误检查,正如你所说,它只是更简单。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM