patterncsharpMinor
I've started Tuples to LINQ and I'm not sure if it's an anti pattern
Viewed 0 times
linqstartedantisureandnottuplespattern
Problem
I have
I can then do as a trivial example
Obviously the tuple must have the same types throughout. My use
case is where I have a mathematical solver which will always return
two solutions for a given input. Returning a list makes it unclear
how many solutions would be returned.
However in the end I would want all my solutions merged. For example
Is there some good reason not to treat
public static class TupleExtensions {
public static IEnumerable SelectMany(this IEnumerable> te)
{
foreach (var t in te)
{
yield return t.Item1;
yield return t.Item2;
}
}
public static IEnumerable SelectMany(this IEnumerable source, Func> fn)
{
foreach (var s in source)
{
var t = fn(s);
yield return t.Item1;
yield return t.Item2;
}
}
public static IEnumerable SelectMany(this IEnumerable source, Func> fn)
{
foreach (var s in source)
{
var t = fn(s);
yield return t.Item1;
yield return t.Item2;
yield return t.Item3;
}
}
public static IEnumerable SelectMany(this IEnumerable source, Func> fn)
{
foreach (var s in source)
{
var t = fn(s);
yield return t.Item1;
yield return t.Item2;
yield return t.Item3;
yield return t.Item4;
}
}
}I can then do as a trivial example
IEnumerable source = ...
source.SelectMany(i=>Tuple.Create(i, i+1, i+2))Obviously the tuple must have the same types throughout. My use
case is where I have a mathematical solver which will always return
two solutions for a given input. Returning a list makes it unclear
how many solutions would be returned.
However in the end I would want all my solutions merged. For example
static Tuple Intersect(this Shape shape, Line other);
Shape shape = ...
IEnumerable lines = ...
IEnumerable intersections = lines.SelectMany(line=>shape.Intersect(line));Is there some good reason not to treat
Tuple as a container that we can flatten?Solution
In general, I think this pattern makes sense, because it clearly expresses what the method returns and lets you easily do the computation you want to do with the result.
Some thoughts:
-
I don't see any reason why your extension methods should only work on a collection of
Since this would make the code you showed more complicated, it might make sense to also keep
-
It might make sense to create custom types that mean “pair (triple, …) of items of the same type”. As a side benefit, you wouldn't need custom
Some thoughts:
-
I don't see any reason why your extension methods should only work on a collection of
Tuples and not on a single Tuple. Because of that, I would probably write extension methods that convert a single Tuple to IEnumerable:public static IEnumerable ToEnumerable(this Tuple tuple)
{
yield return tuple.Item1;
yield return tuple.Item2;
}Since this would make the code you showed more complicated, it might make sense to also keep
SelectMany(), but express it using ToEnumerable():public static IEnumerable SelectMany(
this IEnumerable> tuples)
{
return tuples.SelectMany(t => t.ToEnumerable());
}
public static IEnumerable SelectMany(
this IEnumerable source, Func> selector)
{
return source.SelectMany(x => selector(x).ToEnumerable());
}-
It might make sense to create custom types that mean “pair (triple, …) of items of the same type”. As a side benefit, you wouldn't need custom
ToEnumerable() or SelectMany() extensions, since those types could implement IEnumerable directly.Code Snippets
public static IEnumerable<T> ToEnumerable<T>(this Tuple<T, T> tuple)
{
yield return tuple.Item1;
yield return tuple.Item2;
}public static IEnumerable<T> SelectMany<T>(
this IEnumerable<Tuple<T, T>> tuples)
{
return tuples.SelectMany(t => t.ToEnumerable());
}
public static IEnumerable<T> SelectMany<T, U>(
this IEnumerable<U> source, Func<U, Tuple<T, T>> selector)
{
return source.SelectMany(x => selector(x).ToEnumerable());
}Context
StackExchange Code Review Q#27586, answer score: 2
Revisions (0)
No revisions yet.