Home > OS >  C#7: How to use tuples in generic methods (LINQ select example)
C#7: How to use tuples in generic methods (LINQ select example)

Time:05-19

I have some heavily repeating code, which has always the same structure, just using different columns in a database for accessing it and doing similar stuff

A typical query looks like:

var portfolioIds = context.PortSelMotorSeries
                    .Select(x => new { x.Id, x.InstallationAltitudeMax })
                    .ToList();

Now I want to use a generic function for dependency inversion and to pass the selector function as a delegate to the query:

private void ForEachIterate<T1>(Func<MotorSeriesDb, T1> selectorFunc): where T1 : (int Id, double Value)
{
  ...
  var portfolioIds = context.PortSelMotorSeries
                        .Select(selectorFunct)
                        .ToList();
  ...
}

So that I can call the query with my own selector:

ForEachIterate(x => new { Id = x.Id, Value = x.InstallationAltitudeMax });
ForEachIterate(x => new { Id = x.Id, Value = x.TemperatureMax });

Specifying the constraint with "where T1 : (int Id, double Value)" leads to a compiler error CS0701.

Leaving it away leads to other compiler errors.

Is there any way to use tuples in generic functions?

CodePudding user response:

For one thing you're confusing tuples (the (int Id, double Value) thing) with anonymous classes (the new { Id = x.Id, Value = x.TemperatureMax }). They aren't even related, so your code would never work as is.

For another, if all you want is to force the user to output a tuple of some specific type, you can do something like this:

private void ForEachIterate(Func<MotorSeriesDb, (int, double)> selectorFunc)
{
  ...
  var portfolioIds = context.PortSelMotorSeries
                        .Select(selectorFunct)
                        .ToList();
  ...
}

// call like:
ForEachIterate(x => (x.Id, x.InstallationAltitudeMax));

Note that there's nothing generic about your function at all. Which leads me to my third point: you're missing the entire point of Linq. You talk about inversion of control, but you're the one who's inverting it in the wrong direction to begin with.

You already have a construct that allows arbitrary selection: context.PortSelMotorSeries. Simply use Linq to select what you want out of it in the call site and you're done.

CodePudding user response:

If you try this it could works:

private static void ForEachIterate<T1>(Func<MotorSeriesDb, T1> selectorFunc) where T1 : Tuple<int, double>
{
    var portfolioIds = context.PortSelMotorSeries
                .Select(selectorFunct)
                .ToList();
}
  • Related