四:江湖学艺(上)
创业帮派项目遇难,引入技术总监人物,力挽狂澜;本人敬之并从其学得武艺
本节开始,语言就不复古了,转成大众话的记述文,不然怕是得拖十年才能写完。
话说当年,我去游乐乐的时候加上我也才4个人,美工2名,加我和技术老大,还有BOSS,凑和5个。
就在我闭头苦B Coding 时,短短数日, 游乐乐人员招聘速度飞快;
转眼间各部门已不断成立,美工一部门,编辑一部门,策划一部门,技术一部门。
BOSS想法也日复一日不断演变中,项目已超出原有的规划,上线日期也不断往后推延。
最神秘的,当属原活动版块负责人神秘失踪后,才新招一人负责,第一天一起吃过中午饭,第二天发现人又失踪了。
由于技术老大和BOSS有朋友关系,说好帮手数月,大体项目差不多就会离开,所以BOSS引入技术总监人物,负责统管技术部。
同时原来的技术老大,则转到开发Ulolo后台管理系统。
技术总监来的第一件事,就是审核项目代码,并找出了项目里“经常黄页”的原因:DataReader关闭问题。
我曾经写过一篇关于DataReader,可以参考:DataReader不奇怪,该出手时就出手!,此文介绍了DataReader本质上的相关内涵信息。
关于DataReader问题,由于项目里多处是Ctrl+C,Ctrl+V,批量代码生成量产,已经散落在各个页面中。
所以技术总监的想法是重写SQLHelper里的SqlDataReader的返回:
通过重写DataReader, 将原来DataReader的数据,快速读取到一个新的容器MDataReader,然后关闭链接再返回。
所以整体项目代码基本不用改动,当年的秋天小白还是按原来的方式编码,继续CTRL+C+V。
这是当年的MDataReader的实现代码:
MDataReader 实现using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
namespace UloloDataFramework.Core.Data
{
public class MDataReader : System.Data.IDataReader, System.Collections.IEnumerable
{
public static implicit operator MDataReader(System.Data.SqlClient.SqlDataReader _SourceDataReader)
{
MDataReader mrdr = new MDataReader();
mrdr.CreateSelf(ref _SourceDataReader);
_SourceDataReader.Close();
_SourceDataReader.Dispose();
return mrdr;
}
//public static implicit operator MDataReader(System.Data.IDataReader _SourceDataReader)
//{
// MDataReader mrdr = new MDataReader();
// mrdr.CreateSelf(ref (SqlDataReader)_SourceDataReader);
// _SourceDataReader.Close();
// _SourceDataReader.Dispose();
// return mrdr;
//}
private System.Collections.Specialized.OrderedDictionary[] _MeList;
private int _MeListI = -1;
private int _BaseListI = 0;
private bool isRead = false;
private int _RecordsAffected = -1;
private int _FieldCount = -1;
public MDataReader()
{
}
public MDataReader(System.Data.IDataReader _SourceDataReader)
{
//MDataReader mrdr = new MDataReader();
this.CreateSelf(ref _SourceDataReader);
_SourceDataReader.Close();
_SourceDataReader.Dispose();
//return mrdr;
}
public MDataReader(System.Data.SqlClient.SqlDataReader _SourceDataReader)
{
//MDataReader mrdr = new MDataReader();
this.CreateSelf(ref _SourceDataReader);
_SourceDataReader.Close();
_SourceDataReader.Dispose();
//return mrdr;
}
public void CreateSelf(ref System.Data.SqlClient.SqlDataReader _SourceDataReader)
{
do
{
if (_SourceDataReader.HasRows)
{
_MeListI++;
System.Array.Resize<System.Collections.Specialized.OrderedDictionary>(ref _MeList, _MeListI + 1);
_MeList[_MeListI] = new System.Collections.Specialized.OrderedDictionary();
_FieldCount = _SourceDataReader.FieldCount;
_RecordsAffected = _SourceDataReader.RecordsAffected;
for (int j = 0; _SourceDataReader.Read(); j++)
{
_MeList[_MeListI].Add(j.ToString(), new ReaderDataItemClass());
for (int i = 0; i < _SourceDataReader.FieldCount; i++)
{
((ReaderDataItemClass)_MeList[_MeListI][j.ToString()]).Add(_SourceDataReader.GetName(i), _SourceDataReader[_SourceDataReader.GetName(i)]);
}
}
}
} while (_SourceDataReader.NextResult());
}
public void CreateSelf(ref System.Data.IDataReader _SourceDataReader)
{
System.Data.SqlClient.SqlDataReader srd = (System.Data.SqlClient.SqlDataReader)_SourceDataReader;
CreateSelf(ref srd);
srd.Close();
srd.Dispose();
}
public bool NextResult()
{
_BaseListI++;
if (_BaseListI > _MeListI)
{
Dispose();
return false;
}
else
{
_MeList[_BaseListI - 1].Clear();
_MeList[_BaseListI - 1] = null;
isRead = false;
return true;
}
}
public bool Read()
{
try
{
if (!isRead)
{
isRead = true;
return (_MeList[_BaseListI].Count == 0) ? false : true;
}
((ReaderDataItemClass)_MeList[_BaseListI][0]).Clear();
_MeList[_BaseListI][0] = null;
_MeList[_BaseListI].RemoveAt(0);
return (_MeList[_BaseListI].Count == 0) ? false : true;
}
catch { return false; }
}
public object this[int index]
{
get
{
return ((ReaderDataItemClass)_MeList[_BaseListI][0])[index];
}
}
public object this[string key]
{
get
{
return ((ReaderDataItemClass)_MeList[_BaseListI][0])[key];
}
}
public bool HasRows
{
get
{
return (_MeList[_BaseListI].Count == 0) ? false : true;
}
}
public void Dispose()
{
_MeList = null;
}
public void Close()
{
_MeList = null;
}
#region IDataRecord 成员
public int FieldCount
{
get { return _MeList == null ? 0 : ((ReaderDataItemClass)_MeList[_BaseListI][0]).Count; }
}
public bool GetBoolean(int i)
{
return bool.Parse(((ReaderDataItemClass)_MeList[_BaseListI][0])[i].ToString());
}
public byte GetByte(int i)
{
return byte.Parse(((ReaderDataItemClass)_MeList[_BaseListI][0])[i].ToString());
}
public long GetBytes(int i, long fieldOffset, byte[] buffer, int bufferoffset, int length)
{
return 0;
}
public char GetChar(int i)
{
return char.Parse(((ReaderDataItemClass)_MeList[_BaseListI][0])[i].ToString());
}
public long GetChars(int i, long fieldoffset, char[] buffer, int bufferoffset, int length)
{
return 0;
}
public string GetDataTypeName(int i)
{
return (((ReaderDataItemClass)_MeList[_BaseListI][0])[i].GetType().Name);
}
public DateTime GetDateTime(int i)
{
return DateTime.Parse(((ReaderDataItemClass)_MeList[_BaseListI][0])[i].ToString());
}
public decimal GetDecimal(int i)
{
return decimal.Parse(((ReaderDataItemClass)_MeList[_BaseListI][0])[i].ToString());
}
public double GetDouble(int i)
{
return double.Parse(((ReaderDataItemClass)_MeList[_BaseListI][0])[i].ToString());
}
public Type GetFieldType(int i)
{
return (((ReaderDataItemClass)_MeList[_BaseListI][0])[i].GetType());
}
public float GetFloat(int i)
{
return float.Parse(((ReaderDataItemClass)_MeList[_BaseListI][0])[i].ToString());
}
public Guid GetGuid(int i)
{
return new Guid((((ReaderDataItemClass)_MeList[_BaseListI][0])[i].ToString()));
}
public short GetInt16(int i)
{
return short.Parse(((ReaderDataItemClass)_MeList[_BaseListI][0])[i].ToString());
}
public int GetInt32(int i)
{
return int.Parse(((ReaderDataItemClass)_MeList[_BaseListI][0])[i].ToString());
}
public long GetInt64(int i)
{
return long.Parse(((ReaderDataItemClass)_MeList[_BaseListI][0])[i].ToString());
}
public string GetName(int i)
{
return ((ReaderDataItemClass)_MeList[_BaseListI][0]).Keys[i].ToString();
}
public int GetOrdinal(string name)
{
System.Collections.ArrayList tmpList = ((ReaderDataItemClass)_MeList[_BaseListI][0]).Keys;
return tmpList.IndexOf(name);
}
public string GetString(int i)
{
return ((ReaderDataItemClass)_MeList[_BaseListI][0])[i].ToString();
}
public object GetValue(int i)
{
return ((ReaderDataItemClass)_MeList[_BaseListI][0])[i];
}
public int GetValues(object[] values)
{
for (int i = 0; i < values.Length; i++)
{
values[i] = ((ReaderDataItemClass)_MeList[_BaseListI][0])[i];
}
return values.Length;
}
public bool IsDBNull(int i)
{
return (TypeCode)((ReaderDataItemClass)_MeList[_BaseListI][0])[i] == System.TypeCode.DBNull;
}
#endregion
#region IDataReader 成员
public int Depth
{
get { return 0; }
}
public DataTable GetSchemaTable()
{
DataTable dt = new DataTable();
object[] tmpObj = null;
for (int i = 0; i < ((ReaderDataItemClass)_MeList[_BaseListI][0]).Count - 1; i++)
{
dt.Columns.Add(this.GetName(i));
}
while (this.Read())
{
((ReaderDataItemClass)_MeList[_BaseListI][0]).CopyTo(tmpObj, 0);
dt.Rows.Add(tmpObj);
}
return dt;
}
public bool IsClosed
{
get { return true; }
}
public int RecordsAffected
{
get { return _RecordsAffected; }
}
#endregion
#region IDataRecord 成员
public IDataReader GetData(int i)
{
throw new Exception("ERR");
}
#endregion
#region IEnumerable 成员
public IEnumerator GetEnumerator()
{
return new System.Data.Common.DbEnumerator(this);
}
#endregion
}
class ReaderDataItemClass : System.Collections.Specialized.OrderedDictionary, System.Collections.Specialized.IOrderedDictionary
{
private System.Collections.ArrayList _KeyList;
public ReaderDataItemClass()
: base()
{
_KeyList = new System.Collections.ArrayList();
}
public new System.Collections.ArrayList Keys
{
get { return _KeyList; }
}
public new void Add(object key, object value)
{
_KeyList.Add(key);
base.Add(key, value);
}
public new void Clear()
{
_KeyList.Clear();
base.Clear();
}
public void Remove(int index)
{
_KeyList.RemoveAt(index);
base.RemoveAt(index);
}
}
当年我是小白,连SQLHelper看着都吃力,连存储过程的编写,也是扔给技术老大的,所以对技术总监的实力就很崇拜了。
后来招了一个“副技术总监”,负责了原来的活动模块和新开发论坛模块,还有论坛的编辑器。
当我原有项目基本落定时,前后又完成了几个小项目,犹记得刚完成了“目地的指南”模块时,事情就发生了。
我稍有点闲空时,技术总监突然让我写一个缓存类:
我苦思N小时,基于对控件的熟悉程度,我知道页面有这东东可以设置缓存:
然而写成缓存类,那会小白的我,除了会写个实体类,写其它类,咪咪,一时找不着北,蛋疼了近小时。。。
稍会,技术总监和BOSS开完会后出来,问我写的怎样了,我摸了摸头,说了句无从下手。
然后他花了点时间把缓存类的大体写了下,然后让我看懂了再补充。
我看了看,看到一个List<string>,就看不懂了,问技术总监那个List<T>是什么东东。
总监只回答了两个字“泛型”,我没有再问,在网络搜索泛型,看了相关文章和介绍。
同时当年电脑里存档了这样一份CHM知识库文档,在我闲时,总会抽空看看:
经过多篇文章的学习之后,加上上下左右前中后的扫了多次代码,基本把缓存这块,除了不懂的,能懂的都懂了。
于是一转身,问总监需要加什么功能?
后来大体是要求“缓存优先级别,和界限设置,及按要求定时检测并清空缓存功能”。
基本上前后按总监要求,来回改了N十次,还特别写了个winform界面来测试缓存的稳定性。
2天左右。。一句差不多也算交差了。
那会的源码,好在我的硬盘里有存档,这里顺路提供大伙下载,见识下我当年的潜力:点击下载
那段快速时间,是求知欲最强的时候,和技术总监的交流中,总会遇到一些不明白的词,像“网关”,“VPN”,"DNS“,”Hosts“,"Hook"。
聊的时候我不懂,只能呵呵,总监以为我知道,聊完后回电脑桌边第一件事就是查相关词,了解下是什么东东。
经过不断的搜索,看文章,那时候的智商,看完文章,还是有理解不了词,像”VPN“,”流“,”Hook“。
下篇预告:
四:江湖学艺(下):缓存过后,技术总监让我写MDataTable,不明觉厉。