C#7:如何在泛型方法中使用元组(LINQ select 示例)

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

我有一些重复性很强的代码,它们始终具有相同的结构,只是使用数据库中的不同列来访问它并执行类似的操作

典型的查询如下所示:

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

现在我想使用通用函数进行依赖倒置,并将选择器函数作为委托传递给查询:

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

以便我可以使用自己的选择器调用查询:

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

使用“where T1 : (int Id, double Value)”指定约束会导致编译器错误 CS0701。

离开它会导致其他编译器错误。

有没有办法在泛型函数中使用元组?

如果您尝试这样做,它可能会起作用:

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

一方面,您将元组((int Id, double Value) 的东西)与匿名 类(new { Id = x.Id, Value = x.TemperatureMax } 的东西)混淆了。它们甚至不相关,因此您的代码永远不会按原样运行。

另一方面,如果你只想强制用户输出某种特定类型的元组,你可以这样做:

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

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

请注意,您的函数根本没有通用性。这引出了我的第三点:您错过了 Linq 的全部要点。你说的是控制反转,但你一开始就把它反转到了错误的方向。

您已经有了一个允许任意 selection 的结构:context.PortSelMotorSeries。只需在调用站点中使用 Linq select 您想要的内容即可。