What is the most intuitive way to ask for objects in pairs?

Therefore, I need to create a class that works with a set of paired objects. Between objects there is a one-to-one comparison. I expect the class client to establish this mapping before using my class.

My question is, what is the best way to give a user of my class the opportunity to provide me with this information?

Can I request a collection of such pairs?

MyClass(IEnumerable<KeyValuePair<Object, Object>> objects) 

Or separate collections like this?

 MyClass(IEnumberable<Object> x, IEnumerable<Object> y) 

Or is there another option?

I like the first, because the relationship is obvious, I do not like it because of the extra work that he puts on the client.

I like the second, because types are more primitive and require less work, I don't like this because the mapping is not explicit. I must assume that the order is correct.

Opinions please?

+6
design c # usability
source share
12 answers

In .NET 4, you should use Tuple<T1,T2> . Additional information on the Tuple class on MSDN.

+10
source share

If you have access to it, use Tuple<T, R> . If you do not, just write a generic Tuple or Pair class. I would not use KeyValuePair , simply because it is verbose and has a connection with Dictionary .

+5
source share

I would prefer KeyValuePair of the two you mentioned, as it is more expressive and maintains a connection between objects.

But I would prefer to create a class containing a link to your pair. This is more readable, in my opinion, and it never hurts to create an additional class or structure to express your actual actions.

(pseudo code)

 class MyPair { public TypeA One; public TypeB Two; } MyClass(IEnumerable<MyPair> objects) 

Some answers mention Tuple<,> , which reads as KeyValuePair, but more flexible since it can contain more than two parameters.

[Edit - more indupth about Tuples / classes after a good night’s sleep]

To a tuple or not to a tuple

+5
source share

The first is my preferred method, since one sequence can be longer than the second with the second - it does not support the required 1: 1 mapping.

+1
source share

In my opinion, the second option gives you and the client more work. The first option is safer and harder to make mistakes. I would choose the first option or something like that every time.

+1
source share

I would prefer the first one. As you say, the correlation is explicit, and it is less error prone than the second, where you need to check that both collections are the same length. Of course, it may actually be appropriate to suggest / both / ways, depending on which class you are building.

One thing, if you are using .NET 4.0, I would recommend using Tuple<T1, T2> instead of KeyValuePair.

+1
source share

I think you need to go with option 1. There must be an explicit relationship, or you just ask for problems.

0
source share

I would use the second version (because it is simpler) + comments + static / dynamic checks. If you can use code contracts, try to make sure the collections are the same length, not null. If not, then do the same with Debug.Assert , as well as if ... throw ArgumentException . In addition, you can create your own object containing a pair, but then it becomes more difficult if you want to use generics for members of a pair. In addition, when you create an object to be stored in a container, you must correctly implement GetHashCode , Equals , etc. The first book, Effective C #, has an element.

As a rule, I prefer not to relearn method signatures.

0
source share

I usually provide both with the KeyValuePair constructor delegating to the 2-arg constructor. The best of both worlds.

0
source share

I like the first method for two reasons.

  • If they already store their relationships in a Dictionary <> object, they can simply cancel the dictionary as is - no additional code is required.

  • If they use their own storage, then providing KeyValuePairs in IEnumerable is very simple with the yield statement

Something like that:

 IEnumerable<KeyValuePair<Object,Object>> GetMappedPairs() { foreach( var pair in _myCustomData ) { yield return new KeyValuePair{Key = pair.ID, Value = pair.Data}; } } 

Parameter 2 is not well understood by developers using your method, so documentation and comments are required to explain how to use it.

By the way, you most likely will like it best by declaring your method as general, not hard KeyValuePair code

 MyClass<TKey,TValue>( IEnumerable<KeyValuePair<TKey,TValue>> pairs ); 
0
source share

It might be worth considering why you expose the enumerable at all. You can use the Add method (Object a, Object b), which completely hides your internal way of communicating with couples. Then, the client could establish its own means of adding relationships to it, both with settings and individually.

Of course, if you still need an enumerated method, then the first option is probably best: an explicit relation. But you consider using or using a type of Tuple or Pair instead of KeyValuePair, assuming that the relationship between them is not one of the Key to Value properties.

0
source share

What if you did something like that?

 // The client can choose to put together an IEnumerable<...> by hand... public MyClass(IEnumerable<KeyValuePair<object, object>> pairs) { // actual code that does something with the data pairs } // OR the client can pass whatever the heck he/she wants, as long as // some method for selecting the Xs and Ys from the enumerable data is provided. // (Sorry about the code mangling, by the way -- just avoiding overflow.) public static MyClass Create<T> (IEnumerable<T> source, Func<T, object> xSelector, Func<T, object> ySelector) { var pairs = source .Select( val => new KeyValuePair<object, object>( xSelector(val), ySelector(val) ) ); return new MyClass(pairs); } 

This will allow customers to write code as follows:

 // totally hypothetical example var stockReturns = StockReturns.Create(prices, p => p.Close, p => p.PrevClose); 
0
source share

All Articles