Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 562715
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 13, 20262026-05-13T12:35:02+00:00 2026-05-13T12:35:02+00:00

Update 2011-Jan-06: Believe it or not, I went ahead and incorporated this interface into

  • 0

Update 2011-Jan-06:

Believe it or not, I went ahead and incorporated this interface into an open source library I’ve started, Tao.NET. I wrote a blog post explaining this library’s IArray<T> interface, which not only addresses the issues I originally raised in this question (a year ago?!) but also provides a covariant indexed interface, something that’s sorely lacking (in my opinion) in the BCL.


Question (in short):

I asked why .NET has IList<T>, which implements ICollection<T> and therefore provides methods to modify the list (Add, Remove, etc.), but doesn’t offer any in-between interface such as IArray<T> to provide random access by index without any list modification.


EDIT 2010-Jan-21 2:22 PM EST:

In a comment to Jon Skeet’s original answer (in which he questioned how often one would have any need for a contract such as IArray<T>), I mentioned that the Keys and Values properties of the SortedList<TKey, TValues> class are IList<TKey> and IList<Value>, respectively, to which Jon replied:

But in this case it’s declared to be
IList and you know to just use the
indexers. . . . It’s not hugely
elegant, I agree – but it doesn’t
actually cause me any pain.

This is reasonable, but I would respond by saying that it doesn’t cause you any pain because you just know you can’t do it. But the reason you know isn’t that it’s clear from the code; it’s that you have experience with the SortedList<TKey, TValue> class.

Visual Studio isn’t going to give me any warnings if I do this:

SortedList<string, int> mySortedList = new SortedList<string, int>();

// ...

IList<string> keys = mySortedList.Keys;
keys.Add("newkey");

It’s legal, according to IList<string>. But we all know, it’s going to cause an exception.

Guillaume made an apt point as well:

Well, the interfaces aren’t perfect
but a dev can check the IsReadOnly
property before calling
Add/Remove/Set…

Again, this is reasonable, BUT: does this not strike you as a bit circuitous?

Suppose I defined an interface as follows:

public interface ICanWalkAndRun {
    bool IsCapableOfRunning { get; }

    void Walk();
    void Run();
}

Now, suppose as well that I made it a common practice to implement this interface, but only for its Walk method; in many cases, I would opt to set IsCapableOfRunning to false and throw a NotSupportedException on Run…

Then I might have some code that looked like this:

var walkerRunners = new Dictionary<string, ICanWalkAndRun>();

// ...

ICanWalkAndRun walkerRunner = walkerRunners["somekey"];

if (walkerRunner.IsCapableOfRunning) {
    walkerRunner.Run();
} else {
    walkerRunner.Walk();
}

Am I crazy, or is this kind of defeating the purpose of an interface called ICanWalkAndRun?


Original Post

I find it very peculiar that in .NET, when I am designing a class with a collection property that provides random access by index (or a method that returns an indexed collection, etc.), but should not or cannot be modified by adding/removing items, and if I want to “do the right thing” OOP-wise and provide an interface so that I can change the internal implementation without breaking the API, I have to go with IList<T>.

The standard approach, it seems, is to go with some implementation of IList<T> that explicitly defines the methods Add, Insert, etc. — typically by doing something like:

private List<T> _items;
public IList<T> Items {
    get { return _items.AsReadOnly(); }
}

But I kind of hate this. If another developer is using my class, and my class has a property of type IList<T>, and the whole idea of an interface is: “these are some available properties and methods”, why should I throw a NotSupportedException (or whatever the case may be) when he/she tries to do something that, according to the interface, should be completely legal?

I feel like implementing an interface and explicitly defining some of its members is like opening a restaurant and putting some items on the menu — perhaps in some obscure, easy-to-miss part of the menu, but on the menu nonetheless — that are simply never available.

It seems there ought to be something like an IArray<T> interface that provides very basic random access by index, but no adding/removing, like the following:

public interface IArray<T> {
    int Length { get; }
    T this[int index] { get; }
}

And then IList<T> could implement ICollection<T> and IArray<T> and add its IndexOf, Insert and RemoveAt methods.

Of course, I could always just write this interface and use it myself, but that doesn’t help with all the pre-existing .NET classes that don’t implement it. (And yes, I know I could write a wrapper that takes any IList<T> and spits out an IArray<T>, but … seriously?)

Does anyone have any insight into why the interfaces in System.Collections.Generic were designed this way? Am I missing something? Is there a compelling argument against what I’m saying about my issues with the approach of explicitly defining members of IList<T>?

I’m not trying to sound cocky, as if I know better than the people who designed the .NET classes and interfaces; it just doesn’t make sense to me. But I’m ready to acknowledge there’s plenty I probably haven’t taken into consideration.

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-13T12:35:02+00:00Added an answer on May 13, 2026 at 12:35 pm

    Design questions are not always black and white.

    One side is exact interfaces for each situation, which makes the whole process of actually implementing interfaces a real pain.

    The other is few(er) multi-purpose interfaces which aren’t always fully supported by the implementor but make many things easier, such as passing instances around which are similar but would not get the same interfaces assigned in the “exact interface” design.

    So the BCL designers chose to go the second way. Sometimes I also wish that interfaces were a little less multi-purpose, especially for the collections and with the C#4 interface co-/contravariance features (which cannot be applied to most collection interfaces escept for IEnumerable<> because they contain both co- as well as contravariant parts).

    Also, it’s a shame that the base classes such as string and the primitive types do not support some interfaces such as ICharStream (for strings, which could be used for regex etc. to allow using other sources than string instances for pattern matching) or IArithmetic for numeric primitives, so that generic math would be possible. But I guess that all frameworks have some weak points.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

UPDATE 2011.09.13 This bug has been resolved by Adobe. The example code below now
(update) ICustomTypeDescriptor works for my Windows Forms app, but not for Silverlight; Not supported.
Update: This does work, I was being stupid :( i have the following extension
UPDATE!!! Suggested answer is NOT correct, my mistake. The #container DIV should've had float:left;.
********Update to Question********** If the tableview does not affect the model: Are the index
Update: Based on the answers I initially went the route of using IsInstanceOf() which
Update: This is, as I was told, no principle Python related problem, but seems
UPDATE 9th june 2012: Setup with mongoid 3.0.0.rc at heroku, see this gist: https://gist.github.com/2900804
Using the following steps: (I have checked this similar post , which does not
When I execute INSERT ON DUPLICATE KEY UPDATE (IODKU) in Mysql command line interface,

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.