IList and IReadOnlyList

后端 未结 4 1966
小鲜肉
小鲜肉 2021-02-01 02:20

If I have a method that requires a parameter that,

  • Has a Count property
  • Has an integer indexer (get-only)

What should the type

4条回答
  •  猫巷女王i
    2021-02-01 02:27

    If you're more concerned with maintaining the principal of DRY over performance, you could use dynamic, like so:

    public void Do(IList collection)
    {
        DoInternal(collection, collection.Count, i => collection[i]);
    }
    public void Do(IReadOnlyList collection)
    {
        DoInternal(collection, collection.Count, i => collection[i]);
    }
    
    private void DoInternal(dynamic collection, int count, Func indexer)
    {
        // Get the count.
        int count = collection.Count;
    }
    

    However, I can't say in good faith that I'd recommend this as the pitfalls are too great:

    • Every call on collection in DoInternal will be resolved at run time. You lose type safety, compile-time checks, etc.
    • Performance degradation (while not severe, for the singular case, but can be when aggregated) will occur

    Your helper suggestion is the most useful, but I think you should flip it around; given that the IReadOnlyList interface was introduced in .NET 4.5, many API's don't have support for it, but have support for the IList interface.

    That said, you should create an AsList wrapper, which takes an IReadOnlyList and returns a wrapper in an IList implementation.

    However, if you want to emphasize on your API that you are taking an IReadOnlyList (to emphasize the fact that you aren't mutating the data), then the AsReadOnlyList extension that you have now would be more appropriate, but I'd make the following optimization to AsReadOnly:

    public static IReadOnlyList AsReadOnly(this IList collection)
    {
        if (collection == null)
            throw new ArgumentNullException("collection");
    
        // Type-sniff, no need to create a wrapper when collection
        // is an IReadOnlyList *already*.
        IReadOnlyList list = collection as IReadOnlyList;
    
        // If not null, return that.
        if (list != null) return list;
    
        // Wrap.
        return new ReadOnlyWrapper(collection);
    }
    

提交回复
热议问题