Why does .NET not provide a class for a List<KeyValuePair<T, U>>
?
I think开发者_C百科 there are a lot of situations when you need to keep an array of pairs. For example,
1; 2 "a"; "array"
5; 8 "b"; "browser"
1; 9 "f"; "Firefox"
8; 10 "f"; "frequency"
À la:
Pairs<int, int> myPairs;
myPairs.Add(10, 8);
myPairs.Add(5, 8);
myPairs.Add(10, 5);
myPairs.Add(1, 4);
myPairs[0].Value1 = 5;
myPairs[5].Value2 = 8;
This seems completely unnecessary to me - and just because you have a pair of values doesn't mean it's necessarily a key/value relation either.
.NET 4 introduced the Tuple
family of types... unless this really was a key/value pair, I'd use List<Tuple<T1, T2>>
instead - and I see no reason for a single type to exist in order to encapsulate that construct.
EDIT: To put this into context, here's how "difficult" it is to use Tuple
here, converting your sample code:
var myPairs = new List<Tuple<int, int>> {
Tuple.Create(10, 8),
Tuple.Create(5, 8),
Tuple.Create(10, 5),
Tuple.Create(1, 4),
};
Now tuples are immutable, so you wouldn't be able to set the values directly as per the last part of your code... but the beauty of composing the two concepts of "list" and "pair of values" is that you could easily write your own MutableTuple
type and use exactly the same code... whereas if you had one collection class which was hard-wired to Tuple
or some other type, you wouldn't have that flexibility.
Why stop there? Why not a list of triplets? Or quadruplets?
The fact is that this is very trivial to write yourself. Write a class that derives from List<KeyValuePair<TKey, TValue>>
, add an Add
method that takes 2 parameters.
public class KeyValueList<TKey, TValue> : List<KeyValuePair<TKey, TValue>>
{
public void Add(TKey key, TValue value)
{
Add(new KeyValuePair<TKey, TValue>(key, value));
}
}
Boom, you're done.
Further comments: Note that KeyValuePair<TKey, TValue>
is an immutable type (as is Tuple<T1, T2>
in .NET 4.0); so if you'd want to be able to do something like this:
list[0].Value = 5;
...then you'd need a mutable type, something like:
public sealed class Pair<T1, T2>
{
public T1 X { get; set; }
public T2 Y { get; set; }
}
public class PairList<T1, T2> : List<Pair<T1, T2>>
{ /* ...same as KeyValueList<T1, T2>, basically... */ }
Also note that this would enable nice initialization syntax:
var list = new PairList<int, string>
{
{ 1, "dan" },
{ 2, "serhio" }
};
But again, the point here is that this is very easy and very trivial and thus not really deserving of its own type in the framework. Look at it this way: can you name any type in the BCL that is essentially just another type but with one single convenience method added?
Closing comments: You have posed these questions:
- Why introduce a
List<T>
type when you could just use aT[]
array? - Why introduce a
Dictionary<TKey, TValue>
type when you could just use aList<KeyValuePair<TKey, TValue>>
?
These are bizarre questions, honestly. Why introduce OOP at all when you can just do everything with procedural code and global variables? Why introduce higher-level programming languages like C#, C++, or even C when you could just write everything in Assembly?
The List<T>
class provides a useful encapsulation of all the functionality that goes into accessing elements in an array, maintaining the number of items, resizing the array as necessary, etc. There is a big difference between what you can do with a List<T>
and what you can do with just a T[]
.
The Dictionary<TKey, TValue>
also encapsulates the functionality of maintaining a collection of values associated with unique keys. It also provides killer O(1) lookup time on those keys. There is a huge difference between a Dictionary<TKey, TValue>
and a List<KeyValuePair<TKey, TValue>>
.
The difference between a List<KeyValuePair<TKey, TValue>>
and your proposed KeyValueList<TKey, TValue>
(as I've called it above) is practically nil. Hardly anything new is encapsulated. It just is a List<T>
. Honestly the benefit is, to me, hardly greater than adding an Int32List
type that just wraps a List<int>
.
There's just no reason to add such a type to the BCL.
What's stopping you from using a List<KeyValuePair<T, V>>
directly? And, if you know T
and V
, you can alias it at the top of your source file:
using KeyValueList = System.Collections.Generic.List<System.Collections.Generic.KeyValuePair<MyNS.MyKeyType, MyNS.MyValueType>>;
// in your code...
KeyValueList list = new KeyValueList();
list.Add(new KeyValuePair<MyKeyType, MyValueType>(..., ...));
You may be looking for Dictionary<TKey,TValue>
:
Represents a collection of keys and values.
Dictionary<TKey,TValue>
is a specialized collection that is optimized for key/value pairs. While you are free to create a List<KeyValuePair<TKey,TValue>>
, you are short-changing yourself as you will not have optimized access to your keys are values.
You could use System.Collections.Specialized.NameValueCollection
, that's a KeyValue store ;)
It's pure (string, string)
mapping, but then most key value situations would work with that.
Or make a subclass of System.Collections.Specialized.NameObjectCollectionBase
for a special solution for your object type.
精彩评论