有时候,我们项目做多了,尤其是网站项目做多了,就会觉得基础知识好像没多大用,但殊不知,对一些基础概念理解不深,就会带来问题。整理下项目中因为基础概念理解不深造成的问题,希望能给以启发。
1.引用类型存储问题
我们知道引用类型存储在堆中,将一个引用类型赋值给另外一个引用类型时,两者指向的是同一个对象,对任何一个变量的修改都会影响到另外一个变量的值。如果单拿这句话或者是应对面试中的题目,大家理解都没问题。但落实到具体项目中,加上一些复杂的逻辑,如果对这话理解不深,就会造成一些问题。下面是项目中犯错的一个真实案例。
引用类型赋值修改问题
static void Main(string[] args)
{
RefTypeCache rtc = new RefTypeCache();
rtc.ShowDatas("B");
rtc.ShowDatas("A");
rtc.ShowDatas("B");
Console.Read();
}
public class RefTypeCache
{
/// <summary>
/// 不同类型用户操作数据
/// </summary>
public void ShowDatas(string userType)
{
DataTable dt = this.GetUserData();
//A类用户想显示下用户积分,就在新赋值的dt中加了一列积分列
if (userType == "A")
{
dt.Columns.Add("score");
Console.WriteLine("A类用户获取到的数据中有积分列:" + dt.Columns.Contains("score"));
}
//B类用户直接显示就好了,不加积分列
if (userType == "B")
{
Console.WriteLine("B类用户获取到的数据中有积分列:" + dt.Columns.Contains("score"));
}
}
/// <summary>
/// 获取数据
/// </summary>
private DataTable GetUserData()
{
DataTable dt = null;
System.Web.Caching.Cache cache = System.Web.HttpRuntime.Cache;
string cacheName = "alldata";
object o = cache.Get(cacheName);
//有缓存则从缓存种获取
if (o != null)
{
dt = o as DataTable;
}
//无缓存则初始化数据
if(dt == null)
{
dt = new DataTable();
dt.Columns.Add("id");
dt.Columns.Add("datas");
DataRow dr0 = dt.NewRow();
dr0["id"] = "1";
dr0["datas"] = "张三";
dt.Rows.Add(dr0);
DataRow dr1 = dt.NewRow();
dr1["id"] = "2";
dr1["datas"] = "李四";
dt.Rows.Add(dr1);
DataRow dr2 = dt.NewRow();
dr2["id"] = "3";
dr2["datas"] = "赵六";
dt.Rows.Add(dr2);
cache[cacheName] = dt;
}
return dt;
}
}
{
RefTypeCache rtc = new RefTypeCache();
rtc.ShowDatas("B");
rtc.ShowDatas("A");
rtc.ShowDatas("B");
Console.Read();
}
public class RefTypeCache
{
/// <summary>
/// 不同类型用户操作数据
/// </summary>
public void ShowDatas(string userType)
{
DataTable dt = this.GetUserData();
//A类用户想显示下用户积分,就在新赋值的dt中加了一列积分列
if (userType == "A")
{
dt.Columns.Add("score");
Console.WriteLine("A类用户获取到的数据中有积分列:" + dt.Columns.Contains("score"));
}
//B类用户直接显示就好了,不加积分列
if (userType == "B")
{
Console.WriteLine("B类用户获取到的数据中有积分列:" + dt.Columns.Contains("score"));
}
}
/// <summary>
/// 获取数据
/// </summary>
private DataTable GetUserData()
{
DataTable dt = null;
System.Web.Caching.Cache cache = System.Web.HttpRuntime.Cache;
string cacheName = "alldata";
object o = cache.Get(cacheName);
//有缓存则从缓存种获取
if (o != null)
{
dt = o as DataTable;
}
//无缓存则初始化数据
if(dt == null)
{
dt = new DataTable();
dt.Columns.Add("id");
dt.Columns.Add("datas");
DataRow dr0 = dt.NewRow();
dr0["id"] = "1";
dr0["datas"] = "张三";
dt.Rows.Add(dr0);
DataRow dr1 = dt.NewRow();
dr1["id"] = "2";
dr1["datas"] = "李四";
dt.Rows.Add(dr1);
DataRow dr2 = dt.NewRow();
dr2["id"] = "3";
dr2["datas"] = "赵六";
dt.Rows.Add(dr2);
cache[cacheName] = dt;
}
return dt;
}
}
从上面的例子可以看出,缓存中的对象赋值给其他变量后,对赋值变量做了修改,从而改变了缓存对象的值,造成了程序的异常。
2.对象实例化
我们知道new ClassName(),就实例化了一个对象,对象中的一些变量如int型就会有默认初值。但在这稍不小心,还会出现问题。一个具体实例是这样出现的,其伪代码如下:
View Code
UserEntity user = new UserEntity(); //用户实体
BillEntity bill = new BillEntity(); //用户钱变动实体
//如果满足条件,给用户加钱,同时生成消费明细
if (condition)
{
bill.UserID = UserID;
bill.SetMoney = 5;
bill.CreateTime = DateTime.Now;
bill.Type = 0; //类型为赠送
}
//修改用户资料
UserBiz ub = new UserBiz();
ub.Update(user);
//如果有帐号变动就增加消费明细记录
//这里的问题在于以为没给bill实体赋值,就以为bill为null,
//却忽略了new BillEntity()后,已经为bill分配了内存,bill变量已经有了储值
if (bill != null)
{
BillBiz bb = new BillBiz();
bb.Add(bill);
}
BillEntity bill = new BillEntity(); //用户钱变动实体
//如果满足条件,给用户加钱,同时生成消费明细
if (condition)
{
bill.UserID = UserID;
bill.SetMoney = 5;
bill.CreateTime = DateTime.Now;
bill.Type = 0; //类型为赠送
}
//修改用户资料
UserBiz ub = new UserBiz();
ub.Update(user);
//如果有帐号变动就增加消费明细记录
//这里的问题在于以为没给bill实体赋值,就以为bill为null,
//却忽略了new BillEntity()后,已经为bill分配了内存,bill变量已经有了储值
if (bill != null)
{
BillBiz bb = new BillBiz();
bb.Add(bill);
}
上面两个例子很简单,大家可能一下子就发现问题的所在,觉得很难犯这样的错误,但这种问题是开发过程中真实存在的,如果对基础概念理解的不够,再加上复杂的逻辑,可能就会犯奇奇怪怪的错误,所以.NET基础知识还是不能忽视的。