History of Commissioning (Linq)

Hmm~ Let's talk about Linq in this article!

I said before that Lambda has finally evolved to the point of heinous:

Func<string, int> returnLength;
returnLength = text => text.Length;

Console.WriteLine(returnLength("Hellow"));

Come on, take out this lambda expression ( text => text.Length ), it looks familiar, it seems to have been used somewhere.

*LINQ

This thing is by far the best expression I've seen, it's not a silver bullet, but it's a very powerful weapon in your development "arsenal".

Let's talk about the composition of Linq first.

collection.linqoperator(delegate, method, lambda);

E.g:

list<int>.Select(x => x == 0);

Select: The loop collection condition is that every int in the collection is equal to 0;

Let's talk about how linq is composed.

Forget it, look directly at the source code of linq. Select's ha

public static IEnumerable<TResult> Select<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector)

The static method has this description as an extension method, this is in front of IEnumerable, an extension method of IEnumerable<TResult>, the parameter is a generic delegate of Func<TSource, TResult>.

Since the parameter is a delegate, the parentheses of linq can be put in a qualified method, a similar delegate, or a lambda expression.

One of the most commonly used is Lambda expressions. Because it is the ultimate evolution of commission, the easiest one.

Linq has a lazy loading feature. At first I thought it was the reason for the delegation (because the delegation is only executed when the Invoke is executed), and then I went to the Internet to check the information.

Discovered that lazy loading is completely achieved by a yield return.

Let's take a look at this weird thing. . .

public IEnumerable<int> OutValue(List<int> list)
{
     foreach (var a in list)
     {
        Console.WriteLine(a);
        yield return a;
     }
}

This is a method of yield return to return IEnumerable, the content is very simple to output the value in the collection, and then yield return.

Then it's weird when I call it.

test.OutValue(list);

output:

Hmm~, try another way of thinking, since you don't output anything, then let me cycle again and see!

var val = OutValue (list);

foreach (var a in val){}

I did not add any operations, just a simple loop. The output is instead:

Humph, obvious. Lazy loading is due to this yield.

If we want to simply implement a Select, it's very simple:

  public static IEnumerable<TResult> Select<TSource,TResult>(this IEnumerable<TSource> source,Func<TSource,TResult> selector)
  {
      foreach (TSource element in source)
         yield return selector(element);
  }

Brutally clear, of course the source code is not like this. . . But the meaning is similar. foreach loops this collection, yield return executes the selector delegate, what is the delegate instance? It is the Lambda, method, and delegate you wear~ Of course, it must meet the conditions.

A yield statement can only appear within an iterator block, which can be used as the body of a method, operator, or accessor. The internal foreach is implemented by iterator plus yield.

When the value returned by Select is used, yield return will execute the Func delegate. Is this how lazy loading works? (Please correct me, my brother may be incorrect, please correct me.)

See how other operators are implemented

*Max maximum value

[__DynamicallyInvokable]
public static int Max(this IEnumerable<int> source)
{
    if (source == null)
    {
        throw Error.ArgumentNull("source");
    }
    int num = 0;
    bool flag = false;
    foreach (int current in source)
    {
        if (flag)
        {
            if (current > num)
            {
                num = current;
            }
        }
        else
        {
            num = current;
            flag = true;
        }
    }
    if (flag)
    {
        return num;
    }
    throw Error.NoElements();
}

Max only supports the expansion of the int set. Is it very simple internally, that is, an int variable to store the maximum value, and a bool type to determine whether the foreach loop is executed.

Let's take a look at the frequently used sorting!

*Groupby

[__DynamicallyInvokable]
public static IEnumerable<IGrouping<TKey, TSource>> GroupBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
{
    return new GroupedEnumerable<TSource, TKey, TSource>(source, keySelector, IdentityFunction<TSource>.Instance, null);
}

But the principle of the final execution is here. . .

[__DynamicallyInvokable, IteratorStateMachine(typeof(Lookup<, >.<GetEnumerator>d__12))]
public IEnumerator<IGrouping<TKey, TElement>> GetEnumerator()
{
    Lookup<TKey, TElement>.Grouping next = this.lastGrouping;
    if (next != null)
    {
        do
        {
            next = next.next;
            yield return next;
        }
        while (next != this.lastGrouping);
    }
    yield break;
}
Lookup<Tkey, TValue> is newly added in .NET3.5, it is similar to Dictionary<Tkey, TElement>, but the key map is brought to a value set. This class is implemented in the program and System.Core, using System, Linq namespace definition. 
Grouping is the program that finally implements sorting. Take the last one, judge that it is not empty, and then do a do{}while() loop. It also uses yield return to delay loading.

  *Where

The delegate in where is different from select;
public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
The return value of the Where delegate is of type bool, but the extension method should return the type of IEnumerable<TSource>. 
Basically it means this:
public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
    foreach (TSource element in source)
    {
       if (predicate(element))
       {
          yield return element;
       }
    }
}

This is roughly the case, as I understand it. Of course, the source code is not like this. Yield returns when the delegate Func is true. It also has the feature of lazy loading. . .

wait wait wait. . . Too many to list.

Then someone will ask, what should I do if I don't want to use this lazy loading, I just want to be like the foreach loop, I just want to load it immediately.

It is definitely possible, and there are requirements that will definitely be met.

It's very simple, just convert the return value to another type. Linq's query operator contains the definition of conversion operations: ToArray (converted to an array), ToDictionary (converted to a dictionary), ToList (converted to a collection), use These conversion operations can convert delayed execution into immediate execution, which can avoid delayed execution.

*Summarize

Just write so much. After all, my understanding is limited, please correct me.

If there are mistakes, you are welcome to point them out, and I will work hard to improve and correct them.

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326014911&siteId=291194637