今天自己在机房重构中使用泛型的时候出现了一个问题,(其实师傅早就要求让用,自己一直恐惧没有开始,今天决定拿一个例子写),在实体类中定义好了数据类型转换函数之后,在D层调用的时候一直弹出“对非共享成员的引用要求对象引用”,什么啊?自己上网查找答案,网上的意思就是说,引用了代码中的非共享成员,但没有提供对象引用。不能使用类名本身来限定非共享成员。实例必须先声明为对象变量,然后才能由变量名引用。也就是我需要将实例声明为对象变量,再按变量名引用实例。
我就纳了闷了,上网查找,看他们的代码里面,没有什么引用啊,为什么到我这里就不行呢?
思索,查找了半天,在纠结了好长时间之后,突然找到了一个关键点,怎么少了一个单词啊,你们知道这个东东是什么吗?
<span style="font-family:KaiTi_GB2312;font-size:18px;"><strong>Public Class DataConvert ''' <summary> ''' 将datatable转换为泛型集合 ''' </summary> ''' <typeparam name="T"></typeparam> ''' <param name="dt"></param> ''' <returns></returns> ''' <remarks></remarks>Of t as {New}是对于T进行约束,约束T的类型 ,公开定义一个可访问的无参构造函数 Public Function DataSetToIlist(Of T As {New})(ByVal dt As DataTable) As IList(Of T) 'IList是泛型,T是泛型中数据类型的确切类型 Dim ds As New List(Of T) '实例化一个泛型集合,用于存放返回的集合 T就是所谓的实体类 Dim type As Type = GetType(T) '定义一个变量,用来返回集合中实体的类型 Dim tempName As String = String.Empty '定义一个临时变量,用来存放datatable中各个属性,初始时为空 Dim dr As DataRow '定义行集 '遍历datatable中的所有的数据行 For Each dr In dt.Rows Dim myT As New T '定义一个实体类对象 '获得实体类中所有属性,并且存放到属性数组中去 Dim Propertys() As System.Reflection.PropertyInfo = myT.GetType().GetProperties() '遍历数组中的所有属性 For Each pi As System.Reflection.PropertyInfo In Propertys tempName = pi.Name '将属性值赋给临时变量 '在datatable中检查是否包含着此列 If dt.Columns.Contains(tempName) Then '判断此列是否可写,如果不可写,则跳出循环 If Not pi.CanWrite Then Continue For End If '如果此列可写,则定义一个列的对象来保存该列 Dim Value As Object = dr(tempName) '如果Value非空,则赋给对象属性值 If Not IsNothing(Value.ToString()) Then Dim a As String = Value.ToString().Trim() pi.SetValue(myT,a,Nothing) '通过反射,动态访问对象的属性 End If End If Next ds.Add(myT) '添加到集合 Next Return ds '返回集合 End Function End Class</strong></span>
如果你细心的会发现,我这里是没有shared的,那么这个单词有那么重要吗?
我们在说这个之前,先来回忆之间C#中的一个单词static,很多人会想这个和shared有关系吗?(其实你知道肯定有关系,不然我不会这么问)。
Static有两种使用情况:
静态分配的,有两种情况:
1. 用在类里的属性、方法前面,这样的静态属性与方法不需要创建实例就能访问,
通过类名或对象名都能访问它,静态属性、方法只有“一份”:即如果一个类新建有N个
2. 方法内部的静态变量:
方法内部的静态变量,执行完静态变量值不消失,再次执行此对象的方法时,值仍存在,
它不是在栈中分配的,是在静态区分析的,这是与局部变量最大的区别;
在此我们主要想说的是第一种情况,也就是static变量及方法不用实例化对象就可以用类名.静态变量和类名.静态方法这种方式进行访问,这使得访问更加方便,不用手工实例化对象。对于某些只读变量和方法来说很适合共享。
我们来看一个实例
<span style="font-family:KaiTi_GB2312;font-size:18px;"><strong>using System; class Employee { public static decimal Salary; // 静态字段 public string Name; // 非静态字段 public static void SetSalary(decimal B) //静态方法 { Salary=B; // 正确,等价于Employee.Salary=B,注意这里不能访问Name变量的,因为它是静态方法 } public void SetName(string N) //非静态方法 { Name=N; // 正确,等价于this.Name=N. } } class Sample { public static void Main() { Employee.Salary=500.0m; // 正确,静态字段可以按类名访问 Employee.SetSalary(500.0m); // 正确,静态方法可以按类名访问 Employee e=new Employee(); // 建立类Employee的一个实例 e.Name="蛙蛙王子"; // 正确,非静态字段必须通过实例访问 e.SetName("蛙蛙王子"); // 正确,非静态方法必须通过实例访问 // 注意,e.Name不能写成Employee.Name,即非静态成员不能按类名访问 // Employee.Salary也不能写成e.Salary,即静态成员不能通过类的实例访问 Console.WriteLine("员工姓名:{0}\n薪水:{1}元",e.Name,Employee.Salary); } }</strong></span>
可以看出用static定义的是可以通过类名直接访问的,而非static定义的需要对其进行实例化然后才能进行访问。
那么这与我们今天说的shared有什么关系呢?
其实说到这里,大家肯定已经知道我少写了什么字,就是shared,那么shared它的作用是什么呢?
Shared关键字是vb.net中用为声明表态变量的,相当于C#中的static关键字,被声明为静态的变量,不需要类的实例就可以通过类直接调用。
如果过程为 Shared,该过程的所有局部变量都自动共享,包括 Static 变量。整个应用程序只有一个这种变量的副本。使用类名调用 Shared 过程,而不是使用指向此类的实例的变量。
也就是说加上shared之后,这个过程或者函数就是共享的,任何其它的调用直接通过类名的调用便可以实现不需要再进行实例化后使用,像数据类型转换只要涉及dataset或者datatable时,在转换时,如果我们不设成shared的,那么我们每次调用时都需要再实例化,然后才能引用该实例,这样很麻烦,但是声明为shared之后便可以通过类名直接访问。就像C#中说static一样,为我们省去很多麻烦,自己理解先到这里,学习还在继续,以后再续~