List分组迭代器

 

说明:

针对长度较大的List对象,可以分组批量进行处理, 如:长度为1000的List对象,可分为10组,每组100条,对数据进行业务逻辑处理...

Source

/******************************************************************************
 * 名称:List分组迭代器
 * 说明:针对长度较大的List对象,可以分组批量进行处理
 * 如:长度为1000的List<int>对象,可分为10组,每组100条,对数据进行业务逻辑处理
 * 作者:Sybs
 * 时间:2018-10-15
 * **************************************************************************/
namespace System.Collections.Generic
{
    /// <summary>
    /// List分组迭代器
    /// </summary>
    public class ListGroupIterator<T>
    {
        private int _groupsize = 1;

        /// <summary>
        /// 分组大小(缺省值为1)
        /// </summary>
        public int GroupSize
        {
            get => _groupsize;
            set => _groupsize = value < 1 ? 1 : value;
        }

        /// <summary>
        /// List数据源
        /// </summary>
        public List<T> Source { get; set; }

        public ListGroupIterator() { }
        public ListGroupIterator(int groupSize) : this(groupSize, null) { }
        public ListGroupIterator(List<T> list) : this(1, list) { }
        public ListGroupIterator(int groupSize, List<T> list)
        {
            this.GroupSize = groupSize;
            this.Source = list;
        }

        /// <summary>
        /// ListGroupIterator迭代器
        /// </summary>
        /// <returns></returns>
        public IEnumerator<List<T>> GetEnumerator()
        {
            if (Source?.Count > 0)
            {
                var ps = Convert.ToInt32(Math.Ceiling(Source.Count * 1.0d / GroupSize));
                var model = Source.Count % GroupSize;
                for (int i = 0; i < ps; i++)
                {
                    var len = ps - i == 1 && model > 0 ? model : GroupSize;
                    yield return Source.GetRange(GroupSize * i, len);
                }
            }
        }

        /// <summary>
        /// 将List<T>实例赋值给ListGroupIterator对象
        /// </summary>
        /// <param name="list"></param>
        public static implicit operator ListGroupIterator<T>(List<T> list)
        {
            return new ListGroupIterator<T> { Source = list };
        }
    }
}

调用

using System;
using System.Collections.Generic;
namespace Demo
{
    class Program
    {
        static void Main()
        {
            ListGroupIterator<int> lg1 = new List<int>() { 1, 2, 3, 4, 5 };
            ListGroupIterator<int> lg2 = new ListGroupIterator<int>(new List<int> { 1, 2, 3, 4, 5 });
            ListGroupIterator<int> lg3 = new ListGroupIterator<int>(3, new List<int>() { 1, 2, 3, 4, 5 });

            lg3.Source.AddRange(new List<int>() { 6, 7, 8, 9 });
            lg3.GroupSize = 2;
            foreach (var item in lg3) { Console.WriteLine(string.Join(",", item)); }
            Console.ReadLine();
        }
    }
}
 
 
 

C#--深入理解类型

 

今日无事,回顾了一下C#基础知识,颇有收获,就自己的理解,写了这篇文章,如有不对,欢迎指正。

C#中的类型可以分为两类:值类型与引用类型,如下图所示。

值类型通常被分配到线程的堆栈上,而引用类型则被分配到托管堆上。例如下面例子:

valuetype和reftype在内存中的位置如下所示:

从上面可以看出,值类型与引用类型的区别在于实际数据的存储位置:

值类型的变量和实际数据都存储在堆栈中;而引用类型只有变量存储在堆栈中,变量储存着实际数据的地址,实际数据储存在与地址相对应的托管堆中。

但是,上边所说的情况并不是绝对的,也就是说值类型的实例不一定分配到线程堆上。

1、应用类型中嵌套定义值类型

以上代码内存分配情况如下:

如果类的字段类型是值类型,他将作为引用类型实例的一部分,被分配到托管堆中。但那些作为局部变量(例子中的c变量)的值类型,则依然会被分配到托管堆中。

2.值类型中嵌套定义引用类型

内存分配如下:

值类型实例总会被分配到它声明的地方,声明的是局部变量时,将分配到栈上,而声明为引用类型成员时,则被分配到托管堆上;而引用类型实例总是被分配到托管堆上。

值类型与引用类型除了在内存上分布方面的区别,还有以下几个方面的区别:

1、值类型继承自ValueType,ValueType又继承自System.Object;而引用类型则直接继承自System.Object;

2、值类型不收GC(垃圾回收器)控制,作用域结束时操作系统自行释放,从而减少了托管堆的压力;

3、若值类型是密封的(sealed),你将不能把值类型作为其他任何类型的基类;而引用类型则一般具有继承性,这里指的是类和接口;

4、值类型不能为null,他会默认初始化为数值0;而引用类型默认情况下会初始化为null值,表示不指向托管堆中的任何地址。对值为null的引用类型的任何操作,都会引发NullReferenceExcption异常;

5、由于值类型包含其实际数据,因此在默认情况下,值类型之间的参数传递不会影响变量自身;而引用类型变量保存的是数据的引用地址,他们作为参数被传递时,参数会发生改变,从影响引用类型变量的值。

两大类型的转换--装箱和拆箱

隐式转换:由低级别类型向高级别类型转换的过程;

显式转换:也叫强制类型转换;

通过is和as运算符进行安全的类型转换;

通过.NET类库中的Convert类来进行类型转换;

装箱拆箱的概念:

装箱:将值类型转换为引用类型的过程;

拆箱:将引用类型转换成值类型的过程;

装箱过程中,系统会在托管堆中生成一份托管堆中值类型对象的副本;而拆箱则是从托管堆中将引用类型所指向的已装箱数据复制回值类型对象的过程。

下面介绍装箱与拆箱过程:

1、装箱过程

具体分为以下三个步骤:

(1)内存分配:在托管堆中分配好内存空间以存放复制的实际数据;

(2)完成实际数据的复制:将值类型的实际数据复制到新分配的内存中;

(3)地址返回:将托管堆中的对象地址返回给引用类型变量;

拆箱过程:

(1)检查实例:首先检查要进行拆箱操作的引用类型变量是否为null,如果为null则抛出NullReferenceException异常;如果不为null则继续检查变量是否和拆箱后的类型是同一类型,若结果为否,会导致InvalidCastException异常。

(2)地址返回:返回已装箱变量的实际数据部分的地址;

(3)数据复制:将托管堆中的实际数据复制到栈中;

总结:

由上面图解可以知道,如果程序中有过多的拆箱装箱操作,由于两个过程都需要进行数据复制,该操作会大量额外运行时间,并且在装箱拆箱过程中必须会产生多余的变量,进一步加重了GC的负担,导致程序的性能降低。

参数传递问题剖析:

1、值类型参数的按值传递:

参数分为两类:形参与实参。形参指的是被调用方法中的参数,也就是说方法定义中的参数为形参;实参指的是调用方法时,传递给对应参数的值。

 

对值类型的按值传递,传递的是该值类型实例的一个副本,也就是说形参接受到的是实参的一个副本,被调用方法操作的是实参的一个副本而已;

2、引用类型的按值传递

当传递的参数是引用类型时,传递和操作的目标是指向对象的地址,而传递的实际内容是对地址的复制。由于地址指向的是实参的值,当方法对地址进行操作时,实际上操作了地址所指向的值,所以调用方法后原来实参的值就会被修改。

3string引用类型参数按值传递的特殊情况

虽然string类型为引用类型,然而在按值传递时,传递的实参却不会因为方法中形参的改变而被修改。

string具有不变形,一个string被赋值,则不能再通过代码去修改它的值。上边代码看似oldStr被赋予了新值“New string”,但实际上内存会重新分配一块内存空间来存放“New string”字符串,然后把分配的内存首地址赋给oldStr变量。

4、值类型和引用类型参数的按引用传递

不管是值类型还是引用类型,你都可以使用ref或out关键字来实现参数的按引用传递。并且在按引用传递时,方法的定义和调用都必须显示的调用ref或out关键字,否则会发生编译错误。

在按引用传递时,不参数是值类型还是引用类型,其本质都是一样的,都是通过ref或out关键字来告诉编译器,方法传递的是参数地址而不是参数本身。

List分组迭代器 C#--深入理解类型的更多相关文章

  1. List分组迭代器

    说明: 针对长度较大的List对象,可以分组批量进行处理, 如:长度为1000的List对象,可分为10组,每组100条,对数据进行业务逻辑处理... Source /**************** ...

  2. python多重继承的属性和方法调用顺序问题和对迭代器的初步理解

    推荐阅读:https://www.cnblogs.com/bigb/p/11650707.html 计算机学习的一个好办法就是自己将代码跑一遍,了解代码的运作顺序和原理(主要弄懂 函数作用,传入参数, ...

  3. C#--深入理解类型

    今日无事,回顾了一下C#基础知识,颇有收获,就自己的理解,写了这篇文章,如有不对,欢迎指正. C#中的类型可以分为两类:值类型与引用类型,如下图所示. 值类型通常被分配到线程的堆栈上,而引用类型则被分 ...

  4. Python:迭代器的简单理解

    一.什么是迭代器 迭代,顾名思义就是重复做一些事很多次(就现在循环中做的那样).迭代器是实现了__next__()方法的对象(这个方法在调用时不需要任何参数),它是访问可迭代序列的一种方式,通常其从序 ...

  5. JavaScript漫谈之理解类型操作符typeof

    在本文中,将简述JavaScript类型系统和数据类型,以及如何使用typeof操作符执行类型检查. 还讲解了使用typeof操作符进行某些数据类型检查是不完善的,并介绍其他几种类型检查的方法. 更多 ...

  6. STL-set 容器以及迭代器的简单理解

    先说下set的基本操作和时间复杂度 begin()     ,返回set容器的第一个元素 end() ,返回set容器的最后一个元素 clear()        ,删除set容器中的所有的元素 em ...

  7. 一步一步的理解C++STL迭代器

    一步一步的理解C++STL迭代器 "指针"对全部C/C++的程序猿来说,一点都不陌生. 在接触到C语言中的malloc函数和C++中的new函数后.我们也知道这两个函数返回的都是一 ...

  8. 带你深入理解STL之迭代器和Traits技法

    在开始讲迭代器之前,先列举几个例子,由浅入深的来理解一下为什么要设计迭代器. //对于int类的求和函数 int sum(int *a , int n) { int sum = 0 ; for (in ...

  9. 如何理解c++迭代器(上)

    1.如何理解迭代器?迭代器不是指针,也似乎不是string这种类型 参考:迭代器与指针的区别是? C++map迭代器的++操作是如何实现的?讨论.iterator提供了遍历STL容器里元素的方式,no ...

随机推荐

  1. 【单调队列】POJ2823-Sliding Window

    单调队列经典题之一. [思路] 设置两个单调队列分别记录最大值和最小值.对于每一个新读入的数字,进行两次操作(对于求最大值和最小值中的某一个而言),一是若队首不在滑窗范围内则删去:二是删去队末比当前值 ...

  2. python基础之re,sys,suprocess模块

    re 正则表达式 1.什么是正则? 正则就是用一系列具有特殊含义的字符组成的规则,该规则用来描述具有某一特征的字符串. 正则就是用来在一个大的字符串匹配出符合规则的子字符串 2.为什么用正则? 正则可 ...

  3. JDK源码学习笔记——HashSet LinkedHashSet TreeSet

    你一定听说过HashSet就是通过HashMap实现的 相信我,翻一翻HashSet的源码,秒懂!! 其实很多东西,只是没有静下心来看,只要去看,说不定一下子就明白了…… HashSet 两个属性: ...

  4. [转]spring security的原理及教程

    Authentication:认证     spring security使用分类: 如何使用spring security,相信百度过的都知道,总共有四种用法,从简到深为:1.不用数据库,全部数据写 ...

  5. Codeforces Gym 100269G Garage 数学

    Garage 题目连接: http://codeforces.com/gym/100269/attachments Description Wow! What a lucky day! Your co ...

  6. 【mybatis】mybatis中避免where空条件后面添加1=1垃圾条件的 优化方法

    在mybatis中拼接查询语句,偶尔会出现where后面可能一个字段的值都没有,就导致所有条件无效,导致where没有存在的意义:但也有可能这些条件会存在.那解决这个问题的方法,最常见的就是: 在wh ...

  7. 3D游戏图形技术解析(7)——视差映射贴图(Parallax Mapping)【转】

    http://www.cnblogs.com/taotaobujue/articles/2781371.html 视差映射贴图(Parallax Mapping) ● 传统纹理贴图的弊端 纹理贴图大家 ...

  8. unity reflection probe --- forward deferred transparent opaque

    deferred 和forward reflection probe 的差别 deferred ref是逐像素的 forward是逐 obj 但我还遇到一个问题就是box projection ref ...

  9. C++11常用特性的使用经验总结(转载)

    C++11已经出来很久了,网上也早有很多优秀的C++11新特性的总结文章,在编写本博客之前,博主在工作和学习中学到的关于C++11方面的知识,也得益于很多其他网友的总结.本博客文章是在学习的基础上,加 ...

  10. 解决NoClassDefFoundError: javax/servlet/jsp/jstl/core/Config

    使用spring3.05 mvc进行开发,使用tomcat容器,通过url映射寻找view的时候,会报错NoClassDefFoundError: javax/servlet/jsp/jstl/cor ...