C# OrderBy-具体是如何实现的?

C# OrderBy-具体是如何实现的?,c#,C#,NET如何知道哪些字段必须排序?根据定义: Enumerable.OrderBy方法(IEnumerable,Func) 字段由Tkey选择,但它只提供字段值,而不提供字段本身。 以下是一个例子: class Cls1 { public string a; public string b; } string keysel2(Cls1 c) { return c.a; } string keysel3(Cls1 c) { return c.b; } 后来我们有: List&l

NET如何知道哪些字段必须排序?根据定义: Enumerable.OrderBy方法(IEnumerable,Func) 字段由Tkey选择,但它只提供字段值,而不提供字段本身。 以下是一个例子:

class Cls1
{
  public string a;
  public string b;
}

string keysel2(Cls1 c)
{
  return c.a;
}

string keysel3(Cls1 c)
{
  return c.b;
}
后来我们有:

List<Cls1> cls1list = new List<Cls1>();

void f()
{
 cls1list.Add(new Cls1 { a = "3", b = "a" });
 cls1list.Add(new Cls1 { a = "2", b = "b" });
 cls1list.Add(new Cls1 { a = "1", b = "c" });

 IEnumerable<Cls1> cls2list = cls1list.OrderBy(keysel2);

 foreach (Cls1 item in cls2list)
 {
    string s = item.a;
    string s1 = item.b;
 }
}
List cls1list=newlist();
void f()
{
添加(新的Cls1{a=“3”,b=“a”});
添加(新的Cls1{a=“2”,b=“b”});
添加(新的Cls1{a=“1”,b=“c”});
IEnumerable cls2list=cls1list.OrderBy(keysel2);
foreach(CLS2列表中的Cls1项)
{
字符串s=项.a;
字符串s1=项b;
}
}

因此OrderBy中没有任何内容直接链接到Cls1的成员字段。编译器如何获取有关实际字段的信息?

您对OrderBy的调用如下:
cls1list.OrderBy(keysel2)

对于cls1list集合中的每一项,OrderBy都将调用keysel2,它返回“a”字符串。OrderBy然后对字符串对调用Compare,这允许它对项目进行排序

您可能没有意识到OrderBy表达式的
keysel2
部分引用的是一个方法,该方法在集合中的每个对象上都被调用-编写此方法的另一种方法是,该方法在功能上是等效的:

cls1list.OrderBy(item=>keysel2(item))

OrderBy正在做类似的事情:

foreach(Cls1 currentItem in items)
{
    Cls1 nextItem = ... (get the next item from items by magic)
    object currentKey = keysel2(currentItem); // This returns a string into currentKey
    object nextKey = keysel2(nextItem); // This returns a string into currentKey

    if(currentKey.Compare(nextKey))
    {
       ... // Swap the items (or not, depending on the ordering you want)
       // Note that OrderBy hasn't looked into the Cls1 items itself at all, it's just looked at the objects it got back from calling keysel2.

    }
}
将key-select委托传递给OrderBy的要点是,这意味着OrderBy根本不需要知道它所排序的对象的类型——它所需要知道的是,如果调用key-select方法,该方法将返回它可以用来决定对象的顺序的内容。您可以将键选择委托视为一种“解释器”——它可以理解Cls1对象,并可以将它们转换为OrderBy可以理解的通用对象。

Func
接受Cls1类型的参数并返回字符串<代码>cls1list.OrderBy(键2)是合法的,因为方法组
keysel2
可以隐式转换为
Func
。在这里,我定义了一个类似的方法并使用了相同的技巧。最后我们得到的只是一个字符串:

    F(keysel2);//Invoke

    string F(Func<Cls1, string> func)
    {
        string orderByResult = func(new Cls1 { a = "4", b = "d" });
        return orderByResult;
    }
F(键2)//援引
字符串F(Func Func)
{
字符串orderByResult=func(新的Cls1{a=“4”,b=“d”});
返回订单ByResult;
}

Func
的实现与
OrderBy
无关。该委托只需与
函数
兼容
OrderBy
将为集合中的每个项目调用委托。它将使用委托返回的值来执行其操作,在本例中是排序。

有一个隐式委托包装您传入的方法
keysel2
,该委托存储您方法的信息,每次需要排序时执行该方法……我真的不明白您的问题是什么。
OrderBy
方法获取一组值,知道它们的类型(因为此信息被编码到传递给它的代理的类型中),并根据代理返回的类型的默认比较器组织调用它所基于的列表中的对象。为什么编译器需要“关于实际字段”的信息?实际上,keysel2返回的是字符串(“a”成员的值),而不是成员本身。我在这里错过了什么?@user628661这正是威尔在回答中所说的。它返回一个字符串,这是成员的值-OrderBy然后比较字符串。如果你让你的keysel方法返回'object',它仍然可以工作。我不明白。OrderBy比较什么字符串?它如何知道与a比较而不是与b比较?@user628661 OrderBy比较传递给它的委托返回的字符串。这将是
a
字符串,因为您传入了
keysel2
,而不是
keysel3