您的位置:首页 > 其它

【ZT】利用反射排序泛型List

2011-01-06 11:29 225 查看
http://xianqiang.blog.163.com/blog/static/45268171200981110488644/

泛型集合List<T>类型转换

List<int> ints = new List<int>();

ints.Add(1);

ints.Add(10);

ints.Add(42);

List<object> objects = new List<object>();

方法一:

参考地址:http://msdn.microsoft.com/zh-cn/library/ms228359(VS.80).aspx

public static void Add<S, D>(List<S> source, List<D> destination) where S : D

{

foreach (S sourceElement in source)

{

destination.Add(sourceElement);

}

}

VarianceWorkaround.Add<int, object>(ints, objects);

方法二:参考MSDN的List<T>成员函数ConvertAll<TOutput>

先看下泛型委托

public delegate void Del<T>(T item);

public static void Notify(int i) { }

Del<int> m1 = new Del<int>(Notify);

C# 2.0 版具有称为方法组转换的新功能,此功能适用于具体委托类型和泛型委托类型,并使您可以使用如下简化的语法写入上一行:

Del<int> m2 = Notify;

说了泛型委托后,言归正传,先定义一个类型转换方法

public static object intToObj(int item)

{//负责把 int 转换成 object 的函数

return (object) item ;

}

就可以直接用ConvertAll<TOutput>方法了

list<object> obj = ints.ConvertAll( new Converter<int,object> (intToObj) )

这样就ok了,完成List<T>的类型转换了

其中 ConvertAll<TOutput>方法是将当前 List<T> 中的元素转换为另一种类型,并返回包含转换后的元素的列表。 方法定义如下:

public List<TOutput> ConvertAll<TOutput>( Converter<T, TOutput> converter)

下面是这个ConvertAll<TOutput>方法用到的委托

public delegate TOutput Converter<TInput, TOutput>( TInput input)

泛型的总结

泛型最常见的用途是泛型集合,命名空间System.Collections.Generic 中包含了一些基于泛型的集合类,使用泛型集合类可以提供更高的类型安全性,还有更高的性能,避免了非泛型集合的重复的装箱和拆箱。

很多非泛型集合类都有对应的泛型集合类,下面是常用的非泛型集合类以及对应的泛型集合类:

非泛型集合类 泛型集合类

ArrayList List<T>

HashTable DIctionary<T>

Queue Queue<T>

Stack Stack<T>

SortedList SortedList<T>

我们用的比较多的非泛型集合类主要有 ArrayList类 和 HashTable类。我们经常用HashTable 来存储将要写入到数据库或者返回的信息,在这之间要不断的进行类型的转化,增加了系统装箱和拆箱的负担,如果我们操纵的数据类型相对确定的化 用 Dictionary<TKey,TValue> 集合类来存储数据就方便多了,例如我们需要在电子商务网站中存储用户的购物车信息( 商品名,对应的商品个数)时,完全可以用 Dictionary<string, int> 来存储购物车信息,而不需要任何的类型转化。

List类

注意:此类在 .NET Framework 2.0 版中是新增的。表示可通过索引访问的对象的强类型列表。提供用于对列表进行搜索、排序和操作的方法。命名空间: System.Collections.Generic,程序集:mscorlib(在 mscorlib.dll 中),List 类是 ArrayList 类的泛型等效类。

//声明一个泛型类

class TestGenericList

...{

static void Main()

...{

//声明一个List对象,只加入string参数

List<string> names = new List<string>();

names.Add("乔峰");

names.Add("欧阳峰");

names.Add("马蜂");

//遍历List

foreach (string name in names)

...{

Console.WriteLine(name);

}

//向List中插入元素

names.Insert(2, "张三峰");

//移除指定元素

names.Remove("马蜂");

}

}

在决定使用 List 还是使用 ArrayList 类(两者具有类似的功能)时,记住 List 类在大多数情况下执行得更好并且是类型安全的。如果对 List 类的类型 T 使用引用类型,则两个类的行为是完全相同的。但是,如果对类型 T 使用值类型,则需要考虑实现和装箱问题。

如果对类型 T 使用值类型,则编译器将特别针对该值类型生成 List 类的实现。这意味着不必对 List 对象的列表元素进行装箱就可以使用该元素,并且在创建大约 500 个列表元素之后,不对列表元素装箱所节省的内存将大于生成该类实现所使用的内存。

其实我们也可以自己定义一个泛型类,如下所示:

//声明一个泛型类

public class ItemList<T>

...{

void Add(T item) ...{ }

}

class TestGenericList

...{

private class ExampleClass ...{ }

static void Main()

...{

// 声明一个对象,只能加入int型

ItemList<int> list1 = new ItemList<int>();

//声明一个对象,只能加入Student类型,Student类为自定义类

ItemList<Student> list2 = new ItemList<Student>();

}

}

泛型的用法还有很多种,如泛型方法,泛型委托,泛型接口等。

List 和 IList的区别 IList <Class1> IList11 =new List <Class1>();

List <Class1> List11 =new List <Class1>();

这两行代码,从操作上来看,实际上都是创建了一个List<Class1>对象的实例,也就是说,他们的操作没有区别。

只是用于保存这个操作的返回值变量类型不一样而已。

那么,我们可以这么理解,这两行代码的目的不一样。

List <Class1> List11 =new List <Class1>();

是想创建一个List<Class1>,而且需要使用到List<T>的功能,进行相关操作。



IList <Class1> IList11 =new List <Class1>();

只是想创建一个基于接口IList<Class1>的对象的实例,只是这个接口是由List<T>实现的。

所以它只是希望使用到IList<T>接口规定的功能而已。

C#里List的用法

主程序代码:

Code

static void Main(string[] args)

{

ClassList listClass = new ClassList();

Console.WriteLine("请输入第个字符串");

string a = Console.ReadLine();

Console.WriteLine("请输入第二个字符串");

string b = Console.ReadLine();

foreach (string n in listClass.strList(a, b))

{

Console.WriteLine(n);

}

类:

class ClassList

{

public List<string> strList(string str1,string str2)

{

string stra = str1 + str2;

string strb = str2 + str1;

string strc = str1 + str1;

List<string> listStr = new List<string>();

listStr.Add(stra);

listStr.Add(strb);

listStr.Add(strc);

return listStr;

}

}

Code

public class Person

{

private string _name;

private string _like;

public string Name

{

get

{

return this._name;

}

set

{

this._name = value;

}

}

public string Like

{

get

{

return this._like;

}

set

{

this._like = value;

}

}

}

IList<Person> myPerson = new List<Person>();

Person person = new Person();

person.Like = "pingpong";

person.Name = "panjun";

myPerson.Add(person);

foreach (Person person1 in myPerson)

{

this.label1.Text += person1.Name + person1.Like;

}

Dictionary

此类在 .NET Framework 2.0 版中是新增的。表示键和值的集合。命名空间:System.Collections.Generic,程序集:mscorlib(在 mscorlib.dll 中)

class TestGenericList

...{

static void Main()

...{

//声明对象,参数表示,键是int类型,值是string类型

Dictionary<int, string> fruit = new Dictionary<int, string>();

try...{

//加入重复键会引发异常

fruit.Add(1, "苹果");

fruit.Add(2, "桔子");

fruit.Add(3, "香蕉");

fruit.Add(4, "菠萝");

//参数错误将引发异常,如下所示

//fruit.Add("5", "aa");

}

catch (ArgumentException)

...{

Console.WriteLine("添加错误!!!");

}

//因为引入了泛型,所以键取出后不需要进行Object到int的转换,值的集合也一样

foreach (int i in fruit.Keys)

...{

Console.WriteLine("键是:{0} 值是:{1}",i,fruit);

}

//删除指定键,值

fruit.Remove(1);

//判断是否包含指定键

if (fruit.ContainsKey(1))

...{

Console.WriteLine("包含此键");

}

//清除集合中所有对象

fruit.Clear();

}

}

Dictionary遍历输出的顺序,就是加入的顺序,这点与Hashtable不同,其它方法如:ContainsKey ,ContainsValue ,Remove 等,使用方法基本一致。

======================================================================================

.NET(C#) Hashtable Dictionary 探索

先看下面的代码

using System;

using System.Collections;

namespace NoSortHashtable

{

/// <summary>

/// Summary description for Class1.

/// </summary>

class Class1

{

/// <summary>

/// The main entry point for the application.

/// </summary>

static void Main(string[] args)

{

Hashtable hashTable = new Hashtable();

hashTable.Add("hunan","changsha");

hashTable.Add("beijing","beijing");

hashTable.Add("anhui","hefei");

hashTable.Add("sichuan","chengdu");

foreach(string str in hashTable.Keys)

{

Console.WriteLine(str + " : " + hashTable);

}

}

}

}

打印的结果是:

anhui : hefei

hunan : changsha

sichuan : chengdu

beijing : beijing

为何产生这样的结果? 我查了MSDN后发现 ----------------------------------------------------------------------------------------------------Hashtable 对象由包含集合元素的存储桶组成。存储桶是 Hashtable 中各元素的虚拟子组,与大多数集合中进行的搜索和检索相比,存储桶可令搜索和检索更为便捷。每一存储桶都与一个哈希代码关联,该哈希代码是使用哈希函数生 成的并基于该元素的键。

哈希函数是基于键返回数值哈希代码的算法。键是正被存储的对象的某一属性的值。哈希函数必须始终为相同的键返回相同的哈希代码。一个哈希函数能够为两个不同的键生成相同的哈希代码,但从哈希表检索元素时,为每一唯一键生成唯一哈希代码的哈希函数将令性能更佳。

在 Hashtable 中用作元素的每一对象必须能够使用 GetHashCode 方法的实现为其自身生成哈希代码。但是,还可以通过使用接受 IHashCodeProvider 实现作为参数之一的 Hashtable 构造函数,为 Hashtable 中的所有元素指定一个哈希函数。

在将一个对象添加到 Hashtable 时,它被存储在存储桶中,该存储桶与匹配该对象的哈希代码的哈希代码关联。在 Hashtable 内搜索一个值时,将为该值生成哈希代码,并且搜索与该哈希代码关联的存储桶。

例如,一个字符串的哈希函数可以采用该字符串中每一字符的 ASCII 代码并它们添加到一起来生成一个哈希代码。字符串“picnic”将具有与字符串“basket”的哈希代码不同的哈希代码;因此,字符串 “picnic”和“basket”将处于不同的存储桶中。与之相比,“stressed”和“desserts”将具有相同的哈希代码并将处于相同的存 储桶中。

Dictionary 类与 Hashtable 类的功能相同。对于值类型,特定类型(不包括 Object)的 Dictionary 的性能优于 Hashtable,这是因为 Hashtable 的元素属于 Object 类型,所以在存储或检索值类型时通常发生装箱和取消装箱操作。

----------------------------------------------------------------------------------------------------

产生这个结果的原因就是Hashtable内部的排序机制使然,但我现在就是不想排序,我按什么顺序输入的,就想它再怎么给我输出,怎么办?google 后发现几个可以解决的办法,不过都需要自己写代码实现比如,继承hashtable,使用不自动排序的arraylist做中间桥

using System;

using System.Collections;

namespace NoSortHashtable

{

public class NoSortHashtable : Hashtable

{

private ArrayList keys = new ArrayList();

public NoSortHashtable()

{

}

public override void Add(object key, object value)

{

base.Add (key, value);

keys.Add (key);

}

public override ICollection Keys

{

get

{

return keys;

}

}

public override void Clear()

{

base.Clear ();

keys.Clear ();

}

public override void Remove(object key)

{

base.Remove (key);

keys.Remove (key);

}

public override IDictionaryEnumerator GetEnumerator()

{

return base.GetEnumerator ();

}

}

}

或者只要Compare函数的返回结果不等于0就可以添加相同的Key,这样可以实现既可以排序,又可以有相同的Key值,可能在某些情况下会用得到。 using System;

using System.Collections;

namespace testSortedList

{

class Class1

{

static void Main(string[] args)

{

SortedList sl = new SortedList(new MySort()); //不排序

sl.Add(333,333);

sl.Add(111,111);

sl.Add(222,222);

sl.Add(111,112);

PrintList(sl);

Console.ReadLine();

}

private static void PrintList(SortedList sl)

{

for(int i=0;i<sl.Count ;i++)

{

Console.WriteLine("{0}\t{1}",sl.GetKey(i),sl.GetByIndex(i));

}//end for

}//end fn()

}

public class MySort:IComparer

{

#region IComparer 成员

public int Compare(object x, object y)

{

return -1;

//排序

// int iResult = (int)x - (int)y;

// if(iResult == 0) iResult = -1;

// return iResult;

}

#endregion

}

}

使用单链接列表实现 IDictionary。建议用于通常包含 10 个或 10 个以下项的集合。

最后我测试了使用泛类型的Dictionary<T,T>, 尽管msdn上说hashtable和Dictionary的实现是一样的,不过同样的数据,返回的结果却是不同的,我没有找到更多的解释,测试代码如下

using System;

using System.Collections;

using System.Collections.Specialized;

using System.Collections.Generic;

namespace NoSortHashtable

{

/// <summary>

/// Summary description for Class1.

/// </summary>

public class Class1

{

/// <summary>

/// The main entry point for the application.

/// </summary>

static void Main(string[] args)

{

Hashtable ht = new Hashtable();

ht.Add("hunan","changsha");

ht.Add("beijing","beijing");

ht.Add("anhui","hefei");

ht.Add("sichuan","chengdu");

foreach(string str in ht.Keys)

{

Console.WriteLine(str + " : " + ht);

}

Console.WriteLine("------------------------------------");

Dictionary<String,String> dic = new Dictionary<String,String>();

dic.Add("hunan","changsha");

dic.Add("beijing","beijing");

dic.Add("anhui","hefei");

dic.Add("sichuan","chengdu");

foreach(string str in dic.Keys)

{

Console.WriteLine(str + " : " + dic);

}

Console.WriteLine("------------------------------------");

ListDictionary lsdic = new ListDictionary();

lsdic.Add("hunan","changsha");

lsdic.Add("beijing","beijing");

lsdic.Add("anhui","hefei");

lsdic.Add("sichuan","chengdu");

foreach(string str in lsdic.Keys)

{

Console.WriteLine(str + " : " + lsdic);

}

}

}

}

另外,System.Collections.Specialized.ListDictionary也是可以完成该要求的,不过。。。

========================================================================================

3個對泛型 List 排序的方法

方式1:

List<SoftDrink> list = manager.SoftDrink.ListSoftDrink();

list.Sort(new MyComp().Compare);

list.Sort(new MyCompDesc().Compare);

public class MyComp : IComparer<SoftDrink> {

public int Compare(SoftDrink x, SoftDrink y) {

return String.Compare(x.SerialId, y.SerialId);

}

}

public class MyCompDesc : IComparer<SoftDrink> {

public int Compare(SoftDrink x, SoftDrink y) {

return String.Compare(y.SerialId, x.SerialId);

}

}

方式2:

list.Sort(

new Comparison<SoftDrink>(

delegate(SoftDrink x, SoftDrink y) {

return String.Compare(x.SerialId, y.SerialId);

}));

list.Sort(

new Comparison<SoftDrink>(

delegate(SoftDrink x, SoftDrink y) {

return String.Compare(y.SerialId, x.SerialId);

}));

方式3: 使用 Dynamic Reflection Library

DynamicComparer<SoftDrink> comparer = new DynamicComparer<SoftDrink>("SerialId");

DynamicComparer<SoftDrink> comparerDesc = new DynamicComparer<SoftDrink>("SerialId DESC");

list.Sort(comparer);

list.Sort(comparerDesc);

在List有90筆 SoftDrink的情況下,對List正排倒排連續做1000次

方法1: 0.424 秒

方法2: 0.393 秒

方法3: 1.859 秒

方法3: 0.527 秒 (如果new Comparer()放在迴圈外)

不要覺得 Dynamic Reflection Library 慢就沒用呀,他能容易的對多屬性做排序,而速度差異也不大

比較糟的是,如果我的物件裏有子物件,我要對依子物件的屬性做排序,他就辦不到了。
http://blog.csdn.net/cxb_wind/archive/2008/04/10/2277670.aspx

C#中List用法

How to find objects in Generics with List.Find() method

I've been looking for help on how to find objects in Generics with List.Find() method .... and ... take a look what I have found.

In the follow example, I created a simple class:

public class Person

{

private int _id;

private string _name;

public int ID { get{ return _id;} set{ _id = value;}}

public int Name { get{ return _name;} set{ _name= value;}}

public Person(int id, string name)

{

_id = id;

_name = name;

}

}

In the example, there's a simple class with two private attributes. Now we're going to create a typed List of this object and take advantage of the Find() method

public void CreateAndSearchList()

{

//create and fill the collection

List<Person> myList = new List<Person>();

myList.Add(new Person(1, "AndreySanches"));

myList.Add(new Person(2, "AlexandreTarifa"));

myList.Add(new Person(3, "EmersonFacunte"));

//find a specific object

Person myLocatedObject = myList.Find(delegate(Person p) {return p.ID == 1; });

}

备注:在list和array集合中搜索元素经常使用该方法,主要技术是泛型委托

list用法注意:如果增加一个对象,必须重新new一个对象,看下面的例子:

person p=new pewson();

for(int i=0;i<5;i++)

{

p.ID=i;

p.Name="xxxx";

list.add(p);

}

for(int i=0;i<5;i++)

{

person p=new person();

p.ID=i;

p.Name="xxxx";

list.add(p);

}

上面有区别吗?在输出list的值是有区别了,第一个list里面存放的都是一样的,结果和最后一个一样,都是同一个人对象,第二个list达到预 期的效果,存储不同的人对象。这是为什么?原因很简单,一个list对象中存储的都是对一个共有的对象进行引用,所以以最后改变的值为准。

对象的排序:本文主要阐述对存储datatable的list进行按TableName排序

1、新建一个sort类

public class SceneSort:IComparer<DataTable>

{

public int Compare(DataTable obj1, DataTable obj2)

{

int tableNameLength1;

int tableNameLength2;

if (obj1 == null)

{

if (obj2 == null)

return 0;

else

return -1;

}

else

{

if (obj2 == null)

return 1;

else

{

tableNameLength1=obj1.TableName.Length;

tableNameLength2=obj2.TableName.Length;

if (Convert.ToInt32(obj1.TableName.Substring(2,tableNameLength1-2))>Convert.ToInt32(obj2.TableName.Substring(2,tableNameLength2-2)))

return 1; //大于返回1

else if (Convert.ToInt32(obj1.TableName.Substring(2,tableNameLength1-2))<Convert.ToInt32(obj2.TableName.Substring(2,tableNameLength2-2)))

return -1; //小于返回-1

else

return 0; //相等返回0

}

}

}

2 排序:

List<DataTable> ldt = new List<DataTable>();

SceneSort ss=new SceneSort ();

tablelist.sort(ss);即可对list进行排序;

/article/5494807.html

利用反射排序泛型List

在最近一个项目中,有需求要对页面中所有的gridview添加排序功能。由于gridview的数据源绑定的是一个集合类List,而不是DataTable,所以无法使用DataView排序功能。另外,不同的gridview显示的是不同的业务数据,为了重用代码只能添加一个泛型方法,使用该方法对数据类型T,按照任意给定的属性进行排序。由于是要按照某个不固定的属性对List内的对象进行排序,所以修改类型T,使之实现IComparable接口,并利用List类的Sort () 方法进行排序是无法满足需求的。但是List类还提供了另一个Sort方法,它接受一个IComparer对象作为参数,在IComparer内可以实现排序的业务逻辑。唯一需要的就是进行排序的属性了,而这个在程序的上下文是已知的。
  思路已经有了,但动手写代码前,google了一下相关文章,竟然发现有一段功能类似的代码,唯一不同是该该代码的实现中方法并不是泛型的。但是强大的地方是,代码中对实现的排序支持按照多个属性排序。于是稍加修改,一段强大的支持按照多属性对List进行排序的泛型方法就出炉了。

  首先是表示排序属性和排序方向的类SortClass,其中保存了排序的属性和排序的方向。

代码private List<T> TableToList<T>(T obj, DataTable tt)
{
System.Type type = obj.GetType();
List<T> list = new List<T>();
for (int i = 0; i < tt.Rows.Count; i++)
{
T item = (T)Activator.CreateInstance(type);

object value;

foreach (DataColumn c in tt.Columns)
{
value = tt.Rows[i][c];
if (value != System.DBNull.Value)
{
type.GetProperty(c.ColumnName).SetValue(item, tt.Rows[i][c], null);
}
}

list.Add(item);
}
return list;
}1. System.Type type = obj.GetType(); 获取类型信息,例如,你想把DataTable最后转换为List<Product>,那么这里的T 的Type就是Product.

2. List<T> list = new List<T>(); 定义你要返回的列表,如上面提到的
List<Product>,因为DataTable的每一行的数据就可以填充一个对象,DataTable所有的数据当然就得返回为List了。

3 . T item = (T)Activator.CreateInstance(type); 根据之前获取的类型信息创建一个实例,你在程序中用的肯定就是对象的实例。

4..

object value;

foreach (DataColumn c in tt.Columns)
{
value = tt.Rows[i][c];
if (value != System.DBNull.Value)
{
type.GetProperty(c.ColumnName).SetValue(item, tt.Rows[i][c], null);
}
}

看到 type.GetProperty(c.ColumnName).SetValue(item, tt.Rows[i][c], null);分解如下:

type.GetProperty(c.ColumnName)(通过属性的名字) 获取之前创建的那个实例的属性的信息,注意:你的实体类的的属性名必须和数据库中表的列名一样。

SetValue(item, tt.Rows[i][c], null); 给属性赋值

OK
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: