有没有办法定义一种 "generic" 函数用作 linq 顺序选择器

Is there a way to define a kind of "generic" func to use as a linq order selector

我有一个简单的对象列表,我想应用不同的过滤器和顺序选择器。过滤器没问题,但是顺序,我不知道如何定义"generic"选择器。

// The selector is always a bool
Func<MyNode, bool> isChild = x => x.Age < 18;
Func<MyNode, bool> isAdult = x => x.Age >= 18;

// So it's always ok to use
Func<MyNode, bool> isAgeOk = isAdult;

// The sort field can be different type (int, string, ...)
Func<MyNode, string> sortByName = x => x.Name;
Func<MyNode, int> sortByAge = x => x.Age;
Func<MyNode, int> sortById = x => x.Id;

// --------------> Is there a way to use a kind of generic declaration Func<MyNode, T> ?
Func<MyNode, int> currentSort = sortByAge;
// With this declaration, i can't use : Func<MyNode, int> currentSort = sortByName

List<MyNode> LstNodes = new List<MyNode>();
// ...Stuff to get nodes

// If I have this kind of linq, it's ok, but current sort is Fixed (Func<MyNode, int> in this example)
var result = LstNodes.Where(isAgeOk).Distinct().OrderBy(currentSort).ToList();

简单的class定义是

public class MyNode
{   
  public int Id  { get; set; }
  public string Name  { get; set; }
  public int Age { get; set; }          
}

我知道由于编译器错误 CS1662,进一步的声明失败了 "Cannot convert anonymous method block to delegate type 'delegate type' because some of the return types in the block are not implicitly convertible to the delegate return type" 但是否可以定义一种类似于 :

的通用声明
Func<MyNode, T> currentSort = sortByAge; // <-- Fails Compiler error CS1662

或者是否有其他方法可以继续?

我只会使用 lambdas

var list = new List<MyNode>() {
new MyNode(){Id = 1, Name = "name1", Age = 1},
new MyNode(){Id = 2, Name = "name2", Age = 2},
new MyNode(){Id = 3, Name = "name3", Age = 3},
new MyNode(){Id = 4, Name = "name4", Age = 4},
new MyNode(){Id = 5, Name = "name5", Age = 5},
new MyNode(){Id = 6, Name = "name6", Age = 6},
new MyNode(){Id = 7, Name = "name7", Age = 7},
new MyNode(){Id = 8, Name = "name8", Age = 8},
        };

        var result = list.Where(n => n.Age >= 3).OrderBy(n => n.Age).ToList();

Fiddle

你可以使用 IComparable.

https://dotnetfiddle.net/23R97J

    Func<MyNode, IComparable> sortByName = x => x.Name;
    Func<MyNode, IComparable> sortByAge = x => x.Age;
    Func<MyNode, IComparable> sortById = x => x.Id;
    var currentSort = sortByAge;

编辑:就像其他人已经提到的那样,使用 IComparable 而不是我之前建议的 object 会更好。

正如 HimBromBeere 评论的那样,最好的方法是使用 IComparable 类型

代码。

        Func<PersonTest, IComparable> sortByName = x => x.Name;
        Func<PersonTest, IComparable> sortByAge = x => x.Age;
        Func<PersonTest, IComparable> sortByLastName = x => x.LastName;

        // --------------> Is there a way to use a kind of generic declaration Func<MyNode, T> ?
        Func<PersonTest, IComparable> currentSort = sortByName;

您的所有类型都实现了 IComparable。由于 Func 是逆变的,您可以分配 returns 该接口的某个实例的任何委托。

所以这有效:

Func<MyNode, IComparable> myDelegate = myFunctionReturningString;
Func<MyNode, IComparable> myDelegate = myFunctionReturningInt;
Func<MyNode, IComparable> myDelegate = myFunctionReturningBool;

在此处阅读有关反方差的信息:https://docs.microsoft.com/de-de/dotnet/csharp/programming-guide/concepts/covariance-contravariance/using-variance-for-func-and-action-generic-delegates