当前位置:网站首页>Count of C # LINQ source code analysis
Count of C # LINQ source code analysis
2022-07-05 08:43:00 【Lazy Ethan】
Summary
LINQ In the code base Count Method as the key method of data statistics , Often used . In Statistics ,Count Method whether to traverse the whole sequence every time to get the number of sequence elements ,Count Whether there is an optimization mechanism for the content of the method . In order to better understand the working principle of this method , We analyze it from the perspective of source code .
The content of this article is based on C# LINQ Source code analysis Select and
C# LINQ Source code analysis Where Based on , Yes Count Method source code analysis .
Count Methods to introduce
Count The basic function of the method is to obtain the number of elements in the sequence .LINQ The code base provides 2 individual Count The method of overloading is as follows :
| Method name | Basic introduction |
|---|---|
| Count(IEnumerable) | Get the number of elements in the sequence |
| Count(IEnumerable, Func<TSource,Boolean>) | Returns the number of elements in the sequence that meet the condition |
Count Key source code analysis
Count The method is IEnumerable An extended method of , To support a TSource The generic parameter .
public static int Count<TSource>(this IEnumerable<TSource> source)
{
if (source == null)
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source);
}
if (source is ICollection<TSource> collectionoft)
{
return collectionoft.Count;
}
if (source is IIListProvider<TSource> listProv)
{
return listProv.GetCount(onlyIfCheap: false);
}
if (source is ICollection collection)
{
return collection.Count;
}
int count = 0;
using (IEnumerator<TSource> e = source.GetEnumerator())
{
checked
{
while (e.MoveNext())
{
count++;
}
}
}
return count;
}
- If the sequence is empty , Throw an exception ;
- If the sequence is implemented ICollection An instance of an interface , for example List Example , Directly return the Count attribute ;
- If the sequence is I Realization IListProvider An instance of an interface , Calling the GetCount Method , Parameters are passed in by default false,IListProvider The interface is described below ;
- If the sequence is implemented ICollection An instance of an interface , for example List Example , Directly return the Count attribute ;
- If source It's an iterator , And the iterator is not implemented IListProvider, Call the iterator , Then complete the iteration , And count the number of elements .
Count Another overloaded method code of is similar , I won't repeat .
Count How methods work
For inspection Count How the method works , This paper deals with Count Method and its associated content for code extraction , Defined Count2 Method , To increase various log, Specific code appendix .
Realization ICollection Object call of interface Count Method
Student See Appendix .
List<Student> studentList = new List<Student>()
{
new Student("x001", "Tom", "CN-1" , 90),
new Student("x002", "Jack", "CN-1", 88),
new Student("x003", "Mary", "CN-2", 87),
new Student("x004", "Frank", "CN-2", 97),
};
var count = studentList.Count2();
System.Console.WriteLine(count);
The results are as follows :
We can see from the result that , obtain List Number of elements in the object , You don't have to traverse the entire List, Just go back to ICollection Interface Count Property value .
Realization IListProvider Object call of interface Count Method
For one List Generic sequence xx, If there is xx.Where().Count() Call to , We want to filter and calculate the number of elements in one iteration , I don't want to realize through two iterations .
The key to achieving the above goals is IListProvider Interface , It mainly defines ToList,ToArray and GetCount Specification of three methods , This article mainly discusses GetCount Method .
We discussed in the previous article ,LINQ The main implementation basis of is inside the extension method , Use various iterators to implement specific operations , for example Where Methodical WhereListIterator iterator , Can achieve List Element filtering .
IListProvider It is to let various iterators implement GetCount Method , So that GetCount Operations are attached to various iterative operations .
The key codes are as follows , among ToList and ToArray Beyond the scope of this article , Has been omitted .
private sealed partial class WhereListIterator<TSource> : Iterator<TSource>, IIListProvider<TSource>
{
public int GetCount(bool onlyIfCheap)
{
if (onlyIfCheap)
{
return -1;
}
int count = 0;
for (int i = 0; i < _source.Count; i++)
{
TSource item = _source[i];
if (_predicate(item))
{
checked
{
count++;
}
}
}
return count;
}
}
We can see , Sealing class WhereListIterator Realized IIListProvider Medium GetCount, In this method, filtering and counting are combined into one .
List Generic sequence xx.Where().Count() Implementation principle of
List<Student> studentList = new List<Student>()
{
new Student("x001", "Tom", "CN-1" , 90),
new Student("x002", "Jack", "CN-1", 88),
new Student("x003", "Mary", "CN-2", 87),
new Student("x004", "Frank", "CN-2", 97),
};
var count = studentList
.Where2(s=>s.MathResult >= 90)
.Count2();
System.Console.WriteLine(count);
- Get into Where2 Extension method , return WhereListIterator Iterator object .
- Get into Count2 Extension method ,WhereListIterator It's done IIListProvider Method .
- call WhereListIterator Object's GetCount Method ,onlyIfCheap Parameter is false.
- Complete filtering and statistics .
The results are as follows , In line with expectations :
List Generic sequence xx.Select().Count() Implementation principle of
List<Student> studentList = new List<Student>()
{
new Student("x001", "Tom", "CN-1" , 90),
new Student("x002", "Jack", "CN-1", 88),
new Student("x003", "Mary", "CN-2", 87),
new Student("x004", "Frank", "CN-2", 97),
};
var count = studentList
.Select2(s => new {
Name= s.Name, Math = s.MathResult})
.Count2();
System.Console.WriteLine(count);
- Get into Select2 Extension method , return SelectListIterator object
- Get into Count2 Extension method ,SelectListIterator It's done IIListProvider Method .
- call SelectListIterator Object's GetCount Method ,onlyIfCheap Parameter is false.
- Complete projection and statistical operations ,SelectListIterator Class related source code is as follows :
private sealed partial class SelectListIterator<TSource, TResult> : IPartition<TResult>
{
public int GetCount(bool onlyIfCheap)
{
// In case someone uses Count() to force evaluation of
// the selector, run it provided `onlyIfCheap` is false.
int count = _source.Count;
if (!onlyIfCheap)
{
for (int i = 0; i < count; i++)
{
_selector(_source[i]);
}
}
return count;
}
}
List Generic sequence xx.Where().Select().Count() Implementation principle of
In the discussion of the previous article , We have learned ,xx.Where().Select() The filtering and projection operations in will be merged into , adopt WhereSelectListIterator iterator , In a traverse List Generic sequence , Will satisfy Where Conditional elements are projected , One time traversal .
Again WhereSelectListIterator It has also been realized. IIListProvider Generic interface , The code is as follows , among ToList and ToArray Beyond the scope of this article , Has been omitted .
private sealed partial class WhereSelectListIterator<TSource, TResult> : IIListProvider<TResult>
{
public int GetCount(bool onlyIfCheap)
{
// In case someone uses Count() to force evaluation of
// the selector, run it provided `onlyIfCheap` is false.
if (onlyIfCheap)
{
return -1;
}
int count = 0;
for (int i = 0; i < _source.Count; i++)
{
TSource item = _source[i];
if (_predicate(item))
{
_selector(item);
checked
{
count++;
}
}
}
return count;
}
}
It's not hard to see from the code that ,GetCount Method will filter , Projection and statistical elements , In one traversal .
therefore , The implementation logic of the following code is very clear , As follows :
List<Student> studentList = new List<Student>()
{
new Student("x001", "Tom", "CN-1" , 90),
new Student("x002", "Jack", "CN-1", 88),
new Student("x003", "Mary", "CN-2", 87),
new Student("x004", "Frank", "CN-2", 97),
};
var count = studentList
.Where2(s=>s.MathResult >= 90)
.Select2(s => new {
Name= s.Name, Math = s.MathResult})
.Count2();
System.Console.WriteLine(count);
- Enter the extension method Where2, return WhereListIterator Iterator instance .
- Enter the extension method Select2,WhereListIterator Is an iterator instance , Call the instance's own Select Method , return WhereSelectListIterator example .
- Enter the extension method Count2,WhereSelectListIterator Realized IIListProvider Interface , So call the instance's own GetCount Method , Will filter , Projection and statistical elements , In one traversal .
The results of the implementation are in line with expectations :

Conclusion
Count The way to deal with List,Array When collecting data types , Will directly return to their implementation ICollection Interface Count Property value ; In and other extension methods Where, Select When used together , The statistical operation and other extended method operations , A merger , Avoid traversing the same sequence multiple times .
appendix
Count2 Method :
public static int Count2<TSource>(this IEnumerable<TSource> source)
{
Console.WriteLine("------------COUNT2-------------------");
if (source == null)
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source);
}
if (source is ICollection<TSource> collectionoft)
{
Console.WriteLine("source is ICollection<TSource> collectionoft");
return collectionoft.Count;
}
if (source is IIListProvider<TSource> listProv)
{
Console.WriteLine("source is IIListProvider<TSource> listProv");
return listProv.GetCount(onlyIfCheap: false);
}
if (source is ICollection collection)
{
Console.WriteLine("source is ICollection collection");
return collection.Count;
}
Console.WriteLine("source is Iterator");
int count = 0;
using (IEnumerator<TSource> e = source.GetEnumerator())
{
checked
{
while (e.MoveNext())
{
count++;
}
}
}
return count;
}
Student class
public class Student {
public string Id {
get; set; }
public string Name {
get; set; }
public string Classroom {
get; set; }
public int MathResult {
get; set; }
}
边栏推荐
- [daily training] 1200 Minimum absolute difference
- Example 002: the bonus paid by the "individual income tax calculation" enterprise is based on the profit commission. When the profit (I) is less than or equal to 100000 yuan, the bonus can be increase
- Sword finger offer 09 Implementing queues with two stacks
- Halcon wood texture recognition
- Old Wang's esp8266 and old Wu's ws2818 light strip
- Arrangement of some library files
- How can fresh students write resumes to attract HR and interviewers
- Matlab tips (28) fuzzy comprehensive evaluation
- [three tier architecture and JDBC summary]
- 猜谜语啦(8)
猜你喜欢

Explore the authentication mechanism of StarUML

Guess riddles (8)

Typescript hands-on tutorial, easy to understand

Lori remote control commissioning record

319. 灯泡开关

Lori remote control LEGO motor

Low code platform | apaas platform construction analysis

资源变现小程序添加折扣充值和折扣影票插件

Example 003: a complete square is an integer. It is a complete square after adding 100, and it is a complete square after adding 168. What is the number?

UE pixel stream, come to a "diet pill"!
随机推荐
Matlab tips (28) fuzzy comprehensive evaluation
One dimensional vector transpose point multiplication np dot
Guess riddles (9)
Arduino burning program and Arduino burning bootloader
2020-05-21
STM32 summary (HAL Library) - DHT11 temperature sensor (intelligent safety assisted driving system)
Program error record 1:valueerror: invalid literal for int() with base 10: '2.3‘
Chapter 18 using work queue manager (1)
Business modeling of software model | stakeholders
实例003:完全平方数 一个整数,它加上100后是一个完全平方数,再加上168又是一个完全平方数,请问该数是多少?
Warning: retrying occurs during PIP installation
Cinq détails de conception du régulateur de tension linéaire
Bluebridge cup internet of things basic graphic tutorial - GPIO input key control LD5 on and off
Pytorch entry record
Hello everyone, welcome to my CSDN blog!
[three tier architecture and JDBC summary]
Guess riddles (4)
L298N module use
Esp8266 interrupt configuration
每日一题——输入一个日期,输出它是该年的第几天