I have code that basically is the same, but depending on the number of arguments you provide (up to 5), it will operate with them in a very repetitive way. I have the feeling that this can be optimized in some way, since maintaining and creating all the overloads by hand is a tedious and error-prone task.
The code is 5 versions (overloads) of the Operate
method. As you can see, it increasingly deal with 2, 3, 4 and 5 arguments (each one is of a given type), so it can adapt from 2 to 5 type arguments.
public static Either<ErrorList, TResult> Operate<T1, T2, TResult>(Either<ErrorList, T1> a, Either<ErrorList, T2> b,
Func<T1, T2, Either<ErrorList, TResult>> onSuccess)
{
var success = from av in a.RightValue
from bv in b.RightValue
select onSuccess(av, bv);
var errorList = new[]
{
a.LeftValue,
b.LeftValue,
}
.SelectMany(x => x.ToEnumerable())
.Aggregate((x, y) => new ErrorList(x.Concat(y)));
return success.ValueOr(() => errorList);
}
public static Either<ErrorList, TResult> Operate<T1, T2, T3, TResult>(Either<ErrorList, T1> a,
Either<ErrorList, T2> b, Either<ErrorList, T3> c,
Func<T1, T2, T3, Either<ErrorList, TResult>> onSuccess)
{
var success =
from av in a.RightValue
from bv in b.RightValue
from cv in c.RightValue
select onSuccess(av, bv, cv);
var errorList = new[]
{
a.LeftValue,
b.LeftValue,
c.LeftValue,
}
.SelectMany(x => x.ToEnumerable())
.Aggregate((x, y) => new ErrorList(x.Concat(y)));
return success.ValueOr(() => errorList);
}
public static Either<ErrorList, TResult> Operate<T1, T2, T3, T4, TResult>(Either<ErrorList, T1> a, Either<ErrorList, T2> b, Either<ErrorList, T3> c, Either<ErrorList, T4> d,
Func<T1, T2, T3, T4, Either<ErrorList, TResult>> onSuccess)
{
var success = from av in a.RightValue
from bv in b.RightValue
from cv in c.RightValue
from dv in d.RightValue
select onSuccess(av, bv, cv, dv);
var errorList = new[]
{
a.LeftValue,
b.LeftValue,
c.LeftValue,
d.LeftValue,
}
.SelectMany(x => x.ToEnumerable())
.Aggregate((x, y) => new ErrorList(x.Concat(y)));
return success.ValueOr(() => errorList);
}
public static Either<ErrorList, TResult> Operate<T1, T2, T3, T4, T5, TResult>(
Either<ErrorList, T1> a,
Either<ErrorList, T2> b,
Either<ErrorList, T3> c,
Either<ErrorList, T4> d,
Either<ErrorList, T5> e,
Func<T1, T2, T3, T4, T5, Either<ErrorList, TResult>> onSuccess)
{
var success = from av in a.RightValue
from bv in b.RightValue
from cv in c.RightValue
from dv in d.RightValue
from ev in e.RightValue
select onSuccess(av, bv, cv, dv, ev);
var errorList = new[]
{
a.LeftValue,
b.LeftValue,
c.LeftValue,
d.LeftValue,
e.LeftValue,
}
.SelectMany(x => x.ToEnumerable())
.Aggregate((x, y) => new ErrorList(x.Concat(y)));
return success.ValueOr(() => errorList);
}
Is there a better way to do this without repeating almost the same code? Imagine that I would like to create another overload for 6, 7, 8... arguments. It can be really tricky and sub-optimal.