ArrayList不显得的来头和解决
分类:计算机编程

背景:无意间蒙受了二个适中的标题,希望对部分境遇的人持有助于!

概述

IEnumerable和IEnumerator接口存在的含义:用来促成迭代的作用!

    public interface IEnumerable
    {
        IEnumerator GetEnumerator();
    }

    public interface IEnumerator
    {
        object Current { get; }

        bool MoveNext();

        void Reset();
    }
一、问题

WinForm DataGridView 绑定泛型List (List<T>)/ArrayList不显示,UI

图片 1

代码如下:

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.OleDb;
using System.IO;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public delegate T BorrowReader<out T>(IDataReader reader);

    public partial class FormMain : Form
    {
        public FormMain()
        {
            InitializeComponent();

        }

        private List<User> GetUsers(IDataReader reader)
        {
            var list = new List<User>();
            while (reader.Read())
            {
                list.Add(new User()
                {
                    ID = reader.GetInt32(reader.GetOrdinal("ID")),
                    UserName = reader.GetString(reader.GetOrdinal("UserName")),
                    NickName = reader.GetString(reader.GetOrdinal("NickName")),
                    Phone = reader.GetString(reader.GetOrdinal("Phone")),
                    QQ = reader.GetString(reader.GetOrdinal("QQ")),
                });
            }
            return list;
        }

        private void btnTest_Click(object sender, EventArgs e)
        {
            dataGridView1.AutoGenerateColumns = false;
            var list = MyDb.LendReader("select * from Users where 0=0", GetUsers);
            dataGridView1.DataSource = list;
        }
    }

    public class User
    {
        public int ID;
        public string UserName;
        public string NickName;
        public string Phone;
        public string QQ;

    }

    public class MyDb
    {
        public static T LendReader<T>(string sql, BorrowReader<T> borrowReader)
        {
            using (OleDbConnection connection = CreateConnection())
            {
                connection.Open();
                OleDbCommand c = new OleDbCommand(sql, connection);
                OleDbDataReader r = c.ExecuteReader();
                return borrowReader(r);
            }
        }

        private static OleDbConnection CreateConnection()
        {
            string dbName = Path.Combine(Application.StartupPath, "MyData.mdb");
            OleDbConnection c = new OleDbConnection
            {
                ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source="   dbName
            };
            return c;
        }
    }
}

迭代的法规

首先来讲一下凑合完结的规律:对于ArrayList、List<T>等集中,类中有贰个个体的数组类型字段,向聚聚焦添增添少时调用Add方法(将数据成分增加到私有数组字段中),而调用类的此外方法时,其实便是对私有数组类型字段的操作。

图片 2图片 3

 1 public class ArrayList : IList, ICollection, IEnumerable, ICloneable
 2 {
 3     //省略其他代码
 4     private object[] _items;
 5     
 6     public virtual int Add(object value)
 7     {
 8         if (this._size == this._items.Length)
 9         {
10             this.EnsureCapacity(this._size   1);
11         }
12         this._items[this._size] = value;
13         this._version  ;
14         return this._size  ;
15     }
16 }

ArrayList

图片 4图片 5

 1 public class List<T> : IList<T>, ICollection<T>, IList, ICollection, IReadOnlyList<T>, IReadOnlyCollection<T>, IEnumerable<T>, IEnumerable
 2 {
 3     //省略其他代码
 4     private T[] _items;
 5     
 6     public void Add(T item)
 7     {
 8         if (this._size == this._items.Length)
 9         {
10             this.EnsureCapacity(this._size   1);
11         }
12         this._items[this._size  ] = item;
13         this._version  ;
14     }
15 }

List

进而对于那些聚焦来讲,本质上聚聚焦的全体因素都是保存在一个私有数组类型的字段中,赫赫有名,对于ArrayList只怕List<T>都得以利用foreach举办迭代,查看集合中的成分。

        static void Main(string[] args)
        {
            List<string> strs=new List<string>();
            strs.Add("DD");
            strs.Add("FF");
            strs.Add("VV");
            strs.Add("WW");
            foreach (String str in strs)
            {
                Console.WriteLine(str);
            }
            Console.ReadKey();
        }

上述那一个foreach的迭代的长河是怎么达成的吗?foreach为何能够每一种遍历所以集结中的元素呢?下边大家就用IL反汇编制程序序来查阅上述代码的foreach部分的IL!

  IL_0039:  callvirt   instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<string>::GetEnumerator()
  IL_003e:  stloc.2
  .try
  {
    IL_003f:  br.s       IL_0052
    IL_0041:  ldloca.s   CS$5$0000
    IL_0043:  call       instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<string>::get_Current()
    IL_0048:  stloc.1
    IL_0049:  nop
    IL_004a:  ldloc.1
    IL_004b:  call       void [mscorlib]System.Console::WriteLine(string)
    IL_0050:  nop
    IL_0051:  nop
    IL_0052:  ldloca.s   CS$5$0000
    IL_0054:  call       instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<string>::MoveNext()
    IL_0059:  stloc.3
    IL_005a:  ldloc.3
    IL_005b:  brtrue.s   IL_0041
    IL_005d:  leave.s    IL_006e
  }  // end .try
  finally
  {
    IL_005f:  ldloca.s   CS$5$0000
    IL_0061:  constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<string>
    IL_0067:  callvirt   instance void [mscorlib]System.IDisposable::Dispose()
    IL_006c:  nop
    IL_006d:  endfinally
  }

看不懂?不妨啦,那么我们就来大约的疑惑一下,我们的foreach生成了那般一大坨的IL中竟然有Enumerator什么的,难道跟这一个有涉嫌呢?凑巧听他们说IEnumerable和IEnumrator用来促成迭代,恰巧巧大家的ArrayList、List<T>集合都以完结了IEnumerable接口。那么大家就来做的勇敢的借使,foreach其实正是施行跟IEnumerable和IEnumrator接口相关的代码,并对保留会集的私有数组字段的目录实行操作,进而来落到实处迭代的功用。

static void Main(string[] args)
{
    List<string> strs=new List<string>();
    strs.Add("DD");
    strs.Add("FF");
    strs.Add("VV");
    strs.Add("WW");
    IEnumerator<string> items = strs.GetEnumerator();
    while (items.MoveNext())
    {
        Console.WriteLine(items.Current);
    }
    Console.ReadKey();
}

这段代码也同样达成了对集合成分迭代的效果!在来看一下以此迭代生成的相干IL。

  IL_0038:  callvirt   instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<string>::GetEnumerator()
  IL_003d:  box        valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<string>
  IL_0042:  stloc.1
  IL_0043:  br.s       IL_0053
  IL_0045:  nop
  IL_0046:  ldloc.1
  IL_0047:  callvirt   instance !0 class [mscorlib]System.Collections.Generic.IEnumerator`1<string>::get_Current()
  IL_004c:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_0051:  nop
  IL_0052:  nop
  IL_0053:  ldloc.1
  IL_0054:  callvirt   instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()
  IL_0059:  stloc.2
  IL_005a:  ldloc.2
  IL_005b:  brtrue.s   IL_0045

哈哈哈,相比较两个生成的IL,目测他们的实行进度中调用的IL指令概况上是相似的(IL指令啥的有时小编亦不是很领会),所以大家的推测应该是正确的,foreach在本质上实在正是通过ArrayList、List<T>中定义的GetEnumerator方法,以至一而再延续的代码完成的!上边就来探视List<T>中是何许定义的。

图片 6图片 7

public class List<T> : IList<T>, ICollection<T>, IList, ICollection, IReadOnlyList<T>, IReadOnlyCollection<T>, IEnumerable<T>, IEnumerable
{
    private T[] _items;
    public List<T>.Enumerator GetEnumerator()
    {
        return new List<T>.Enumerator(this);
    }
    public struct Enumerator : IEnumerator<T>, IDisposable, IEnumerator
    {
        private List<T> list;
        private int index;
        private int version;
        private T current;

        public T Current
        {

            get
            {
                return this.current;
            }
        }

        object IEnumerator.Current
        {

            get
            {
                if (this.index == 0 || this.index == this.list._size   1)
                {
                    ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumOpCantHappen);
                }
                return this.Current;
            }
        }
        internal Enumerator(List<T> list)
        {
            this.list = list;
            this.index = 0;
            this.version = list._version;
            this.current = default(T);
        }

        public void Dispose()
        {
        }

        public bool MoveNext()
        {
            List<T> list = this.list;
            if (this.version == list._version && this.index < list._size)
            {
                this.current = list._items[this.index];
                this.index  ;
                return true;
            }
            return this.MoveNextRare();
        }
        private bool MoveNextRare()
        {
            if (this.version != this.list._version)
            {
                ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);
            }
            this.index = this.list._size   1;
            this.current = default(T);
            return false;
        }

        void IEnumerator.Reset()
        {
            if (this.version != this.list._version)
            {
                ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);
            }
            this.index = 0;
            this.current = default(T);
        }
    }
}    

List<T>

哇哦,原本迭代器是那般的呦!!!!

二、消除措施

实则非常粗大略,只是无尽敌人只怕未有设想到,因为那压根不是哪些泛型List可能ArrayList的标题,

只要改代码:

    public class User
    {
        public int ID;
        public string UserName;
        public string NickName;
        public string Phone;
        public string QQ;
    }

为:

    public class User
    {
        public int ID{ get; set; }
        public string UserName { get; set; }
        public string NickName { get; set; }
        public string Phone { get; set; }
        public string QQ { get; set; } 
    }

就好了

自定义一个差十分的少的支撑迭代的集结

上边我们就来源于定义二个扶持迭代器的集纳

public class UserDefinedCollection<T>:IEnumerable<T>
    {
        private List<T> list = new List<T>();

        public UserDefinedCollection(List<T> param)
        {
            list = param;
        }
        public IEnumerator<T> GetEnumerator()
        {
            return new UserDefinedEnum<T>(list);
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        private sealed class UserDefinedEnum<T>:IEnumerator<T>
        {
            private List<T> list = null;
            private int _CurrentIndex;
            private T _CurrentElement;

            public UserDefinedEnum(List<T> param)
            {
                this.list = param;
                this._CurrentIndex = 0;
                _CurrentElement = default(T);

            }

            public T Current
            {
                get 
                {
                    return _CurrentElement;
                }
            }

            object IEnumerator.Current
            {
                get { return Current; }
            }

            public bool MoveNext()
            {
                if (this._CurrentIndex < this.list.Count)
                {
                    this._CurrentElement = this.list[this._CurrentIndex  ];
                    return true;
                }
                return false;
            }

            public void Reset()
            {
                this._CurrentElement = default(T);
                this._CurrentIndex = 0;
            }
            public void Dispose()
            {

            }
        }

    }

 测量检验自定义集结的迭代功效:

            List<string> strs=new List<string>();
            strs.Add("DD");
            strs.Add("FF");
            strs.Add("VV");
            strs.Add("WW");
            UserDefinedCollection<String> user = new UserDefinedCollection<string>(strs);
            IEnumerator<string> iEnumerator = user.GetEnumerator();

            while (iEnumerator.MoveNext())
            {
                Console.WriteLine(iEnumerator.Current);
            }

            foreach (String str in user)
            {
                Console.WriteLine(str);
            }

 

闻一知十:由模型绑定中,绑定泛型类型时读书到泛型相关的文化!

//调用1
    ExtraGenericInterface(typeof(List<User>),typeof(IEnumerable<>))
    //调用2
    ExtraGenericInterface(typeof(IEnumerable<User>),typeof(IEnumerable<>))

    public Type ExtraGenericInterface(Type queryType, Type interfaceType)
        {
            //当前类型queryType是否是泛型
            bool b = queryType.IsGenericType;
            //返回可以构造当前泛型类型的一个泛型类型,即:由IEnumerable<User>得到 IEnumerable<>
            Type tt = queryType.GetGenericTypeDefinition();

            bool ttt = tt == interfaceType ? true : false;

            Func<Type, bool> predicate = t => t.IsGenericType && (t.GetGenericTypeDefinition() == interfaceType);
            //Func<Type, bool> predicate = delegate(Type queryType2){return false;};
            //如果当前类型是泛型,并且该发行是由interfaceType类型构造的。
            if (predicate(queryType))
            {
                return queryType;
            }
            else
            {
                //获取当前类实现的所有类和接口
                Type[] types = queryType.GetInterfaces();
                //在数组中找,并返回满足 predicate 条件的第一个元素
                //也就是在所有父类或实现的接口中找到是泛型并且构造此泛型的类型是interfaceType类型的第一个元素
         //FirstOrDefault<Type>中Type是后面委托predicate的参数类型 
                Type tttt = types.FirstOrDefault<Type>(predicate);

                return queryType.GetInterfaces().FirstOrDefault<Type>(predicate);
            }

        }

  

三、简单讲明

没概念get、set的是字段,定义了就是性质了,为了安全性考虑,DataGridView 的数据源绑定只好是被公开了的性质,而无权访谈字段。超级多别的控件也是有相符的动静。

本文由pc28.am发布于计算机编程,转载请注明出处:ArrayList不显得的来头和解决

上一篇:福寿康宁劳务端webSocket连接通信 下一篇:没有了
猜你喜欢
热门排行
精彩图文
  • 福寿康宁劳务端webSocket连接通信
    福寿康宁劳务端webSocket连接通信
    前言 近日socket通讯使用TCP、UDP协调,个中TCP公约相对来说相比较安全和谐!本文也是来说学TCP为主(恕在下学艺不精)。      上面是私人商品房精晓的
  • 编写翻译安装javascript,Centos系统一整合体安装
    编写翻译安装javascript,Centos系统一整合体安装
    3,解压安装,设置安装路线 tar zxvf Python-3.6.5.tgz mkdir /usr/local/python365 cd Python-3.6.5 ./configure --prefix=/usr/local/python365 make make install   解释: tar是解压tgz包 ./
  • 如何在手机上实现饼图图表
    如何在手机上实现饼图图表
    最前方的话:Smobiler是一个在VS意况中使用.Net语言来开采APP的开辟平台,也许比Xamarin更低价   生机勃勃、指标准样本式 咱俩要兑现上海教室中的效果,需
  • 并发编程经典实例,并发编程原理与概论
    并发编程经典实例,并发编程原理与概论
    并发编制程序的术语 并发 並且做多件事情 多线程 出现的一种格局,它选用四个线程来实行顺序。 二十三八线程是出现的一种情势,但不是当世无双的款
  • 线程和进程,应用程序域的了然
    线程和进程,应用程序域的了然
    正文主要参照自孙钟秀网编的《操作系统教程》一书中有关进度和线程的局地。 在守旧的操作系统中,进度是系统实行财富分配的单位,由于互相本领、网