为什么.NET中没有IArray(T)接口? [英] Why is there no IArray(T) interface in .NET?

查看:186
本文介绍了为什么.NET中没有IArray(T)接口?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

2011年1月更新:



相信与否,我将这个介面整合到我开始的一个开源库,Tao.NET 。 I 写了一篇博客文章来解释这个库的 IArray< T> 接口,这不仅解决了我最初在这个问题(一年前?!),但也提供了一个协变的索引接口,这在BCL中是非常缺乏的(我认为)。






问题(简​​称):



我问为什么.NET有 IList< T& code>,其实现 ICollection< T> ,因此提供了修改列表的方法( Add code> Remove 等),但不提供任何中间接口,例如 IArray< T>






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



在对Jon Skeet的原始回答的评论中(他询问了如何经常需要一个合同,例如 IArray< T> ),我提到 SortedList< TKey的 Keys Values 属性,TValues> 类别分别是 IList< TKey> IList< Value> Jon回答:


但在这种情况下,它被声明为
IList,你知道只使用
索引器。 。 。 。这不是巨大的
优雅,我同意 - 但它不是
实际上导致我任何痛苦。


这是合理的,但我会回应说,它不会造成任何疼痛,因为你只是知道你不能这样做。但原因你知道不是,从代码中可以清楚;这是你有经验的 SortedList< TKey,TValue> 类。



Visual Studio不会如果我这样做,请给我任何警告:

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

// ...

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

这是合法的,根据 IList< string> 。但是我们都知道,这将导致异常。



Guillaume也做了一个妥协:


好了,接口不是完美的
,但dev可以在调用
之前检查IsReadOnly
属性添加/删除/设置...


同样,这是合理的,:这不会让你觉得有点迂回吗?



假设我定义了一个接口如下:

  public interface ICanWalkAndRun {
bool IsCapableOfRunning {get; }

void Walk();
void Run();
}

现在,假设我做了一个常见的做法来实现这个接口,但仅限于 Walk 方法;在许多情况下,我会选择将 IsCapableOfRunning 设置为 false 并抛出 NotSupportedException 运行 ...



然后我可能会有一些代码看起来像这样: / p>

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

// ...

ICanWalkAndRun walkerRunner = walkerRunners [somekey];

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

我很疯狂,或者是这种击败接口的目的 ICanWalkAndRun






原始帖子



我发现在.NET中,当我设计一个具有通过索引提供随机访问的集合属性的类(或返回索引集合的方法等)时,非常奇怪,但不应或不能通过添加/删除项目修改,如果我想做正确的事情OOP明智和提供一个接口,以便我可以改变内部实现,而不破坏API,必须使用 IList< T>



标准方法看起来是一些实现 IList< T> 明确定义方法 Add 插入等等 - 通常通过做以下操作:

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

但我讨厌这样。如果另一个开发人员使用我的类,并且我的类有一个 IList< T> 类型的属性,并且接口的全部想法是:可用的属性和方法,为什么当他/她试图做某事时,应该抛出一个 NotSupportedException 界面,应该完全合法吗?



我想实现一个界面并明确定义其中的一些成员,就像打开餐厅并在菜单上放置一些项目在菜单中的部分


$

b $ b

看起来应该是一个类似 IArray< T> 接口,它提供了非常基本的索引随机访问,但没有添加/

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

然后 IList< T> 可以实现 ICollection IArray< T> IndexOf 插入 RemoveAt 方法。



当然,我总是可以写这个接口并自己使用它,但这并不能帮助所有的预先存在的.NET类,不实现它。 (是的,我知道我可以写一个包装器,它接受任何 IList< T> 并且输出一个 IArray< T>

有没有人了解为什么 System.Collections.Generic 是这样设计的?我缺少什么?有没有令人信服的论据反对我正在谈论我的问题,明确定义的成员 IList< T> ? >



我并不想听起来很疯狂,好像我比那些设计.NET类和接口的人更了解;它只是没有意义给我

解决方案

设计问题并不总是黑色的,白色。



一方面是每种情况的精确接口,这使得实际实现接口的整个过程变得很痛苦。



另一个是很少的(er)多用途接口,并不总是完全支持实现者,但使许多事情更容易,例如传递类似的实例但不会得到在精确接口设计中分配的相同接口。



因此,BCL设计者选择了第二种方式。有时候我还希望接口有一点少的多用途,特别是对于集合和与C#4接口协同/逆变特征(不能应用于大多数集合接口为IEnumerable <>,因为它们包含co co- /以及逆变部分)。



此外,基类如string和基本类型不支持一些接口,如ICharStream(对于字符串,它可以用于正则表达式等,以允许使用 string 实例进行模式匹配的其他源)或者数字原语的IArithm,以便通用数学是可能的。但我想所有框架都有一些弱点。


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.

解决方案

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.

这篇关于为什么.NET中没有IArray(T)接口?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆