一致性哈希C#简单实现
作者:tupunco 日期:2010-07-24
.NET 源代码
作者:tupunco 日期:2010-06-20
查看.NET Framework的源代码实际也不是什么新鲜的事情, 最简单的可以通过Reflector查看, 不过会有一些语法特征方面的瑕疵, 例如对使用yeild关键字的实现部分, 老赵也在其博客"人肉"过他的编译后的特征. 印象中微软在VS2008SP1前后开放了.NET Framework 的源代码在线调试, ScottGu博客也有过介绍使用的方法, Codeplex 网站也有一个可以下载.NET源代码的工具. 一直以为.NET Framework 源代码也需要那么查看, 最近博客园的一片介绍VS2010的博文使自己发现其源代码微软本身提供下载, 不过博文地址已经不记得了. 直接给出下载地址:
小强下载了两项: .NET 8.0/ .Net 4, 搞不清楚这个8.0 是啥意识, 两个文件包加起来大概200M, 都为MSI格式. 安装后发现这个8.0的实际就是.NET 3.5 SP1 的"所有"Framework源代码, 4 的为.NET 4 Framework源代码. 好像每个版本源代码都是完整的.
使用异步调用来使方法等待执行
作者:tupunco 日期:2010-06-20
编程中使用的数学(2):权重随机
作者:tupunco 日期:2010-05-02
博客也停了半年多了, 半年内好多事情, 时间和机会可能都不适合写下点东西, 2010年了, 开个好头. 之前的一篇写在2008年6月份, 这篇写在一年半以后, 真是个笑话.
步入正题. '权重随机'是去年九十月份工作中一个抽奖问题引出的. 需求需要达到不同奖品需要有不同的获得几率, 在查找资料中找到了以下几篇文章:
- http://zzk.cnblogs.com/s?w=%e6%9d%83%e9%87%8d+%e9%9a%8f%e6%9c%ba&p=1
- 生成安全的随机数 http://www.cnblogs.com/rainy/archive/2006/08/05/468670.html
- http://www.cnblogs.com/wdfrog/archive/2007/12/14/994963.html
按'权重随机'过程假设编程平台上的提供的随机发生器产生的每个结果都是等概率的(实际上.NET平台和其他编程平台上提供了很好的满足本条件的随机发生器), 另外一个条件是'权重'以非负整形数的形式提供. 假如'待随机项'集合为 {I,…,In}, 其对应的权重结合为 {W,…,Wn}, 在产生随机数的时候随机的范围为(0, ∑Wi), 其中∑Wi表示为'所有待随机项权重的和', 使用随机器产生的随机结果假如在 (wi, wi+1] 范围了(注意开闭区间), 则当前的随机结果项为Ii. 可以简单理解为以下的文字描述: 把所有'待随机项'的权重和作为要随机的上限, '随机项'前后排好序, 生成的随机结果如果在某两个个随机项(A,B)权重区间范围内, 那么随机的结果项就取A.
一个线程安全的FIFO缓存容器
作者:tupunco 日期:2010-03-28
项目中需要一个缓存容器, 满足先进先出(FIFO)需求, 容量10000. 参考了几个LRU缓存容器实现, 使用字典(Dictionary)+队列(Queue)组合的方式来达到'插入/删除/读取'复杂度都为O(1), 缓存容器所以需要保持线程安全, 使用简单的lock语句来实现. 下面是实现代码:
1: /// <summary>
2: /// LIFO 容器
3: /// </summary>
4: /// <typeparam name="TKey"></typeparam>
5: /// <typeparam name="TValue"></typeparam>
6: public class ThreadSafeLifoDictionary<TKey, TValue>
7: {
8: private Dictionary<TKey, TValue> _Dict = new Dictionary<TKey, TValue>();
9: private Queue<TKey> _Queue = new Queue<TKey>();
10: private object _LockObj = new object();
11:
12: /// <summary>
13: /// 容量
14: /// </summary>
15: public int Capacity { get; private set; }
16:
17: public ThreadSafeLifoDictionary() : this(10000) { }
18: public ThreadSafeLifoDictionary(int capacity)
19: {
20: this.Capacity = capacity;
21: }
22:
23: /// <summary>
24: /// 当前项数
25: /// </summary>
26: public int Count
27: {
28: get
29: {
30: lock (_LockObj)
31: {
32: return _Queue.Count;
33: }
34: }
35: }
36: /// <summary>
37: /// 清空
38: /// </summary>
39: public void Clear()
40: {
41: lock (_LockObj)
42: {
43: _Queue.Clear();
44: _Dict.Clear();
45: }
46: }
47: /// <summary>
48: /// 添加或更新已有项
49: /// </summary>
50: /// <param name="key"></param>
51: /// <param name="value"></param>
52: /// <returns>添加操作返回true, 更新操作返回false</returns>
53: public bool AddOrUpdate(TKey key, TValue value)
54: {
55: lock (_LockObj)
56: {
57: CheckAndTruncate();
58:
59: if (this._Dict.ContainsKey(key))
60: {
61: this._Dict[key] = value;
62: return false;
63: }
64: else
65: {
66: this._Dict.Add(key, value);
67: this._Queue.Enqueue(key);
68: return true;
69: }
70: }
71: }
72: /// <summary>
73: /// 包含指定项
74: /// </summary>
75: /// <param name="key"></param>
76: /// <returns></returns>
77: public bool ContainsKey(TKey key)
78: {
79: lock (_LockObj)
80: {
81: return _Dict.ContainsKey(key);
82: }
83: }
84: /// <summary>
85: /// 获取指定项
86: /// </summary>
87: /// <param name="key"></param>
88: /// <param name="value"></param>
89: /// <returns></returns>
90: public bool TryGetValue(TKey key, out TValue value)
91: {
92: lock (_LockObj)
93: {
94: return this._Dict.TryGetValue(key, out value);
95: }
96: }
97: /// <summary>
98: /// 达到容量值后删除十分之一的元素
99: /// </summary>
100: private void CheckAndTruncate()
101: {
102: int count = _Dict.Count;
103: if (count >= Capacity)
104: {
105: int needRemoveCount = count / 10;
106: for (int i = 0; i < needRemoveCount; i++)
107: {
108: _Dict.Remove(_Queue.Peek());
109: _Queue.Dequeue();
110: }
111: }
112: }
113: }
对于容量控制部分直接使用了"蛙蛙推荐 LRU"的删除策略, 如果一下只删除一个容量的方式, 会因为频繁创建销毁对象, 而给垃圾回收带来压力.
一个例子:
1: /// <summary>
2: /// 一个使用的例子
3: /// 订阅缓存, 缓存UserID, ChapterID
4: /// </summary>
5: public class SubscribeCacheDemo
6: {
7: ThreadSafeLifoDictionary<string, string> _LifoDict = null;
8: private SubscribeCacheDemo(int capacity)
9: {
10: _LifoDict = new ThreadSafeLifoDictionary<string, string>(capacity);
11: }
12: /// <summary>
13: /// 实例(单件模式访问本缓存对象)
14: /// </summary>
15: public static readonly SubscribeCacheDemo Instance = new SubscribeCacheDemo(100000);
16: /// <summary>
17: /// 订阅
18: /// </summary>
19: /// <param name="userID"></param>
20: /// <param name="ChapterID"></param>
21: /// <returns></returns>
22: public bool Subscribe(int userID, int ChapterID)
23: {
24: return _LifoDict.AddOrUpdate(string.Format("{0}-{1}", userID, ChapterID), string.Empty);
25: }
26: /// <summary>
27: /// 是否订阅过
28: /// </summary>
29: /// <param name="userID"></param>
30: /// <param name="ChapterID"></param>
31: /// <returns></returns>
32: public bool HasSubscribe(int userID, int ChapterID)
33: {
34: return _LifoDict.ContainsKey(string.Format("{0}-{1}", userID, ChapterID));
35: }
36: }
验证码上的高效正弦扭曲函数
作者:tupunco 日期:2010-01-30
c#上, 但凡需要给验证码添加扭曲的地方感觉都是一个函数:
#region 产生波形滤镜效果
private const double PI = 3.1415926535897932384626433832795;
private const double PI2 = 6.283185307179586476925286766559;
/// <summary>
/// 正弦曲线Wave扭曲图片
/// </summary>
/// <param name="srcBmp">图片路径</param>
/// <param name="bXDir">如果扭曲则选择为True</param>
/// <param name="nMultValue">波形的幅度倍数,越大扭曲的程度越高,一般为3</param>
/// <param name="dPhase">波形的起始相位,取值区间[0-2*PI)</param>
/// <returns></returns>
public System.Drawing.Bitmap TwistImage(Bitmap srcBmp, bool bXDir, double dMultValue, double dPhase)
{
System.Drawing.Bitmap destBmp = new Bitmap(srcBmp.Width, srcBmp.Height);
// 将位图背景填充为白色
System.Drawing.Graphics graph = System.Drawing.Graphics.FromImage(destBmp);
graph.FillRectangle(new SolidBrush(System.Drawing.Color.White), 0, 0, destBmp.Width, destBmp.Height);
graph.Dispose();
double dBaseAxisLen = bXDir ? (double)destBmp.Height : (double)destBmp.Width;
for (int i = 0; i < destBmp.Width; i++)
{
for (int j = 0; j < destBmp.Height; j++)
{
double dx = 0;
dx = bXDir ? (PI2 * (double)j) / dBaseAxisLen : (PI2 * (double)i) / dBaseAxisLen;
dx += dPhase;
double dy = Math.Sin(dx);
// 取得当前点的颜色
int nOldX = 0, nOldY = 0;
nOldX = bXDir ? i + (int)(dy * dMultValue) : i;
nOldY = bXDir ? j : j + (int)(dy * dMultValue);
System.Drawing.Color color = srcBmp.GetPixel(i, j);
if (nOldX >= 0 && nOldX < destBmp.Width
&& nOldY >= 0 && nOldY < destBmp.Height)
{
destBmp.SetPixel(nOldX, nOldY, color);
}
}
}
return destBmp;
}
#endregion
这个函数实在效率不高, 但还是很多人用. 可以从下面的地址得到结果:
Tags: 高效 扭曲函数 C# TwistImage 验证码
KCAPTCHA 验证码波纹扭曲函数 C# 实现
作者:tupunco 日期:2010-01-30
KCAPTCHA 一个不错的验证码实现, 官方网站:http://www.captcha.ru/en/kcaptcha/. 因为工作原因, 需要改进验证码所有有机会把波纹扭曲部分使用 C# 实现.
#region KCAPTCHA 波纹扭曲
/// <summary>
/// # KCAPTCHA PROJECT VERSION 1.2.6
/// www.captcha.ru, www.kruglov.ru
/// 波形扭曲 FROM KCAPTCHA
/// </summary>
/// <param name="srcBmp">待扭曲的图像 必须为 PixelFormat.Format24bppRgb 格式图像</param>
/// <returns></returns>
private static Bitmap WaveDistortion(Bitmap srcBmp)
{
if (srcBmp == null)
return null;
if (srcBmp.PixelFormat != PixelFormat.Format24bppRgb)
throw new ArgumentException("srcBmp PixelFormat.Format24bppRgb 格式图像", "srcBmp");
var width = srcBmp.Width;
var height = srcBmp.Height;
Bitmap destBmp = new Bitmap(width, height, PixelFormat.Format24bppRgb);
{
//前景色
Color foreground_color = Color.FromArgb(randx.Next(10, 100), randx.Next(10, 100), randx.Next(10, 100));
//背景色
Color background_color = Color.FromArgb(randx.Next(200, 250), randx.Next(200, 250), randx.Next(200, 250));
using (Graphics newG = Graphics.FromImage(destBmp))
{
newG.Clear(background_color);
// periods 时间
double rand1 = randx.Next(710000, 1200000) / 10000000.0;
double rand2 = randx.Next(710000, 1200000) / 10000000.0;
double rand3 = randx.Next(710000, 1200000) / 10000000.0;
double rand4 = randx.Next(710000, 1200000) / 10000000.0;
// phases 相位
double rand5 = randx.Next(0, 31415926) / 10000000.0;
double rand6 = randx.Next(0, 31415926) / 10000000.0;
double rand7 = randx.Next(0, 31415926) / 10000000.0;
double rand8 = randx.Next(0, 31415926) / 10000000.0;
// amplitudes 振幅
double rand9 = randx.Next(330, 420) / 110.0;
double rand10 = randx.Next(330, 450) / 110.0;
double amplitudesFactor = randx.Next(5, 6) / 10.0;//振幅小点防止出界
double center = width / 2.0;
//wave distortion 波纹扭曲
BitmapData destData = destBmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, destBmp.PixelFormat);
BitmapData srcData = srcBmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, srcBmp.PixelFormat);
for (var x = 0; x < width; x++)
{
for (var y = 0; y < height; y++)
{
var sx = x + (Math.Sin(x * rand1 + rand5)
+ Math.Sin(y * rand3 + rand6)) * rand9 - width / 2 + center + 1;
var sy = y + (Math.Sin(x * rand2 + rand7)
+ Math.Sin(y * rand4 + rand8)) * rand10 * amplitudesFactor; //振幅小点防止出界
int color, color_x, color_y, color_xy;
Color overColor = Color.Empty;
if (sx < 0 || sy < 0 || sx >= width - 1 || sy >= height - 1)
{
continue;
}
else
{
color = BitmapDataColorAt(srcData, (int)sx, (int)sy).B;
color_x = BitmapDataColorAt(srcData, (int)(sx + 1), (int)sy).B;
color_y = BitmapDataColorAt(srcData, (int)sx, (int)(sy + 1)).B;
color_xy = BitmapDataColorAt(srcData, (int)(sx + 1), (int)(sy + 1)).B;
}
if (color == 255 && color_x == 255 && color_y == 255 && color_xy == 255)
{
continue;
}
else if (color == 0 && color_x == 0 && color_y == 0 && color_xy == 0)
{
overColor = Color.FromArgb(foreground_color.R, foreground_color.G, foreground_color.B);
}
else
{
double frsx = sx - Math.Floor(sx);
double frsy = sy - Math.Floor(sy);
double frsx1 = 1 - frsx;
double frsy1 = 1 - frsy;
double newColor =
color * frsx1 * frsy1 +
color_x * frsx * frsy1 +
color_y * frsx1 * frsy +
color_xy * frsx * frsy;
if (newColor > 255) newColor = 255;
newColor = newColor / 255;
double newcolor0 = 1 - newColor;
int newred = Math.Min((int)(newcolor0 * foreground_color.R + newColor * background_color.R), 255);
int newgreen = Math.Min((int)(newcolor0 * foreground_color.G + newColor * background_color.G), 255);
int newblue = Math.Min((int)(newcolor0 * foreground_color.B + newColor * background_color.B), 255);
overColor = Color.FromArgb(newred, newgreen, newblue);
}
BitmapDataColorSet(destData, x, y, overColor);
}
}
destBmp.UnlockBits(destData);
srcBmp.UnlockBits(srcData);
}
if (srcBmp != null)
srcBmp.Dispose();
}
return destBmp;
}
/// <summary>
/// 获得 BitmapData 指定坐标的颜色信息
/// 实现 PHP imagecolorat
/// </summary>
/// <param name="srcData">从图像数据获得颜色 必须为 PixelFormat.Format24bppRgb 格式图像数据</param>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns>x,y 坐标的颜色数据</returns>
/// <remarks>
/// Format24BppRgb 已知X,Y坐标,像素第一个元素的位置为Scan0+(Y*Stride)+(X*3)。
/// 这是blue字节的位置,接下来的2个字节分别含有green、red数据。
/// </remarks>
static Color BitmapDataColorAt(BitmapData srcData, int x, int y)
{
if (srcData.PixelFormat != PixelFormat.Format24bppRgb)
throw new ArgumentException("srcData PixelFormat.Format24bppRgb 格式图像数据", "srcData");
byte[] rgbValues = new byte[3];
Marshal.Copy((IntPtr)((int)srcData.Scan0 + ((y * srcData.Stride) + (x * 3))), rgbValues, 0, 3);
return Color.FromArgb(rgbValues[2], rgbValues[1], rgbValues[0]);
}
/// <summary>
/// 设置 BitmapData 指定坐标的颜色信息
/// 实现 PHP ImageColorSet
/// </summary>
/// <param name="destData">设置图像数据的颜色 必须为 PixelFormat.Format24bppRgb 格式图像数据</param>
/// <param name="x"></param>
/// <param name="y"></param>
/// <param name="color">待设置颜色</param>
/// <remarks>
/// Format24BppRgb 已知X,Y坐标,像素第一个元素的位置为Scan0+(Y*Stride)+(X*3)。
/// 这是blue字节的位置,接下来的2个字节分别含有green、red数据。
/// </remarks>
static void BitmapDataColorSet(BitmapData destData, int x, int y, Color color)
{
if (destData.PixelFormat != PixelFormat.Format24bppRgb)
throw new ArgumentException("destData PixelFormat.Format24bppRgb 格式图像数据", "destData");
byte[] rgbValues = new byte[3] { color.B, color.G, color.R };
Marshal.Copy(rgbValues, 0, (IntPtr)((int)destData.Scan0 + ((y * destData.Stride) + (x * 3))), 3);
}
#endregion
另外一些验证码游优化有关的链接:
- http://www.captcha.ru/en/kcaptcha/ (KCAPTCHA 官方)
- http://zh.wikipedia.org/wiki/CAPTCHA
- http://en.wikipedia.org/wiki/CAPTCHA
- http://caca.zoy.org/wiki/PWNtcha
- http://www.brains-n-brawn.com/default.aspx?vDir=aicaptcha
- http://www.captcha.net/
还有一些验证码识别的链接:
软件开发经典书籍的魅力
作者:tupunco 日期:2009-04-06
读软件开发方面书籍自己似乎有偏好,不喜欢看国内作者写的(不过有好书也是看的,比如博文视点的好多原创经典书籍)大部分看的是国外书籍的译本(英语不好只能看译本),译本也是有选择的,如果是一堆人翻译的基本也不看,除非这本书讲的方面确实就这么一本书,并且翻译的也不赖。博客园有一.NET方面的牛人名叫“老赵”,他的博客格言是“让老外看中国人写的计算机书籍”,甚是敬仰。
过年前后接手的项目是一个“客户端数据录入”的软件,之前开发的都是B/S软件,对WinForm开发中的某些要求也不甚了解,所以按着WEB软件的模式来建立“数据连接层”、“业务逻辑层”。其实自己使用了一个“SocanCode”的代码生成器来生成了“数据连接层”和“业务逻辑层”,由于客户要求的这个客户端软件除了要有一个“中心版”还要一个“部门版”的(软件为什么没有直接设计成B/S版的呢?因为客户的理由是“部门版”的用户可能没有网络,并且点名要搞两个版本),考虑到性能方面的要求所以“部门版”数据库用Access,“中心版”使用SQL Server 2000 个人版,所以这个“代码生成器”生成了两套“数据连接层”代码,真是不错的东西。
“SocanCode”生成的代码类似于“PetShop 4”,模式的代码,“数据实体模型”部分直接就是实体类,软件在实现的时候碰到一个问题:数据库的某些字段的值与其他字段有隐藏的“关联”关系,比如一个XX号=某些字典字段+某些字典字段+自编号。数据库在设计的时候实际上已经违背了某些“数据库设计范式”,因为为了最后呈现的时候方便,也为了客户在导出数据的时候方便。为了实现这个“关联”最后每个“数据实体模型”实现了“System.ComponentModel.INotifyPropertyChanged”接口,来“通知”某些列的更改,通过“PropertyChanged”事件来捕捉“通知”,再“Remove”事件,更改某些“关联”关系的字段值,再“Add”事件来完成整一个“关联”关系字段的控制。虽然实现起来麻烦了点,但客户再提“关联”关系字段更改的需求改的就很方便了。
ASP.NET MVC CRUD 实例
作者:tupunco 日期:2009-03-24
ASP.NET MVC 1.0 已经于上周发布了, RC1的时候写了两个例子, 一个是一个CRUD的例子, 一个是仿蓝色梦想作品集URL路径的例子. CRUD例子是一个拥有完整的从"数据源"查询数据列表/单条详细/删除/更新添加的功能的列子, 仿蓝色梦想作品集URL路径的例子是模仿作品集的URL切换方式, 展示了ASP.NET MVC 功能强大的路由功能, 自定义控件的列子. 本文事CRUD例子的说明和技术细节.
ASP.NET MVC安装/创建项目的方法可以参看http://www.asp.net/mvc的说明教程.
创建项目完毕后, 创建一个数据模型(实际为一数据实体)和数据服务(Fake的数据仓库)部分代码:
namespace MvcApplicationCRUD.Models
{
public class People
{
public int Id { get; set; }
public int Age { get; set; }
public string Name { get; set; }
}
}
[原创]C#中使用反射
作者:tupunco 日期:2009-03-09
过了年到现在忙了起来, 不像年前, 可以整月的闲着, 不过闲着也有好处, 学习了好多东西. 过了年的项目中多次用到了 .Net 反射机制, 使得其间巧妙地解决了很多问题. 总结一下使用到的地方.
1.使用工厂模式来抽象数据连接层之用(PetShop模式的三层结构内的使用方式).
1: System.Reflection.Assembly assembly = Assembly.LoadFile("Assembly Path");
2: IXXXXXDAL dal = (IXXXXXDAL)assembly.CreateInstance("Namespace.DAL.XXXXXDAL");
2.使用 "System.Activator.CreateInstance()" 方式来创建对象.
1: //
2: // 摘要:
3: // 创建类型的一个实例,该类型由指定的泛型类型参数指定。
4: //
5: // 类型参数:
6: // T:
7: // 要创建的类型。
8: //
9: // 返回结果:
10: // 对新创建对象的引用。
11: public static T CreateInstance<T>();
12: //
13: // 摘要:
14: // 使用指定类型的默认构造函数来创建该类型的实例。
15: //
16: // 参数:
17: // type:
18: // 要创建的对象的类型。
19: //
20: // 返回结果:
21: // 对新创建对象的引用。
22: public static object CreateInstance(Type type);
3.显示某对象的子级属性值.
1: public static string DisplayPropertyInfo(object obj)
2: {
3: StringBuilder sb = new StringBuilder();
4: Type type = obj.GetType();
5: sb.AppendFormat("[{0}]\r\n",obj);
6: foreach (var item in type.GetProperties())
7: {
8: sb.AppendFormat("\t[{0}:{1}]\r\n", item.Name,
9: item.GetValue(obj, null));
10: }
11: return sb.ToString();
12: }
4.转换一个DataTable类型的对象成为一个实体集合(Table的列与实体类的属性是一一对应的).
/// <summary>
/// 数据服务基类对象
/// </summary>
public abstract class DataServiceBase
{
#region DB 处理
/// <summary>
/// 执行SQL字符串返回一个DataTable
/// </summary>
/// <param name="sql"></param>
/// <returns></returns>
protected DataTable ExecuteSQL(string sql)
{
//*****返回一个DataTable****
return null;
}
#endregion
#region Tabel 类型转换相关
/// <summary>
/// 转化Table成一个相对应的实体类集合
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="table"></param>
/// <returns></returns>
protected List<T> ConvertDataTableToEntityCollections<T>(DataTable table)
where T : class, new()
{
if (table != null)
{
PropertyInfo[] pInfos = GetTypePropertyInfo(typeof(T));
List<T> list = new List<T>(table.Rows.Count);
foreach (DataRow row in table.Rows)
{
T t = new T();
foreach (var pInfo in pInfos)
{
if (table.Columns.Contains(pInfo.Name))
{
//HACK: 对象转换成指定的类型使用 Convert.ChangeType
// Convert.ChangeType(row[pInfo.Name], pInfo.PropertyType);
try
{
pInfo.SetValue(t, ChangeType(row[pInfo.Name], pInfo.PropertyType), null);
}
catch(Exception ex){
throw ex;
}
}
}
list.Add(t);
}
return list;
}
return null;
}
/// <summary>
/// 得到指定SQL执行的结果并返回结果的实体类集合对象
/// 本方法综合了 ConvertDataTableToEntityCollections/ExecuteSQL 方法
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="sql">待执行的SQL</param>
/// <returns></returns>
protected List<T> GetEntityConllectionsFromSQL<T>(string sql)
where T : class, new()
{
if (string.IsNullOrEmpty(sql))
return null;
else
return ConvertDataTableToEntityCollections<T>(ExecuteSQL(sql));
}
/// <summary>
/// 得到指定类型公开的属性
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
private PropertyInfo[] GetTypePropertyInfo(Type type)
{
PropertyInfo[] infos = null;
//锁定防止 多次 ADD 进缓存
lock (_PROPERTYINFO_READ_LOCK)
{
_PropertyInfoCache.TryGetValue(type, out infos);
if (infos == null)
{
infos = type.GetProperties();
_PropertyInfoCache.Add(type, infos);
}
}
return infos;
}
/// <summary>
/// 类型转换
/// FROM: http://www.cnblogs.com/cnee5/archive/2006/05/21/405403.html
/// </summary>
/// <param name="value"></param>
/// <param name="conversionType"></param>
/// <returns></returns>
public object ChangeType(object value, Type conversionType)
{
//INFO 对DBNull类型特殊处理
if (Convert.IsDBNull(value))
{
//非可空类型的值类型处理
if (!(conversionType.IsGenericType &&
conversionType.GetGenericTypeDefinition().Equals(typeof(Nullable<>))))
return Activator.CreateInstance(conversionType);
else
return null;
}
//可空类型类型处理
if (conversionType.IsGenericType &&
conversionType.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
{
if (value == null)
return null;
System.ComponentModel.NullableConverter nullableConverter
= new System.ComponentModel.NullableConverter(conversionType);
conversionType = nullableConverter.UnderlyingType;
}
return Convert.ChangeType(value, conversionType);
}
private object _PROPERTYINFO_READ_LOCK = new object();
/// <summary>
/// 实体类属性缓存
/// </summary>
private static Dictionary<Type, PropertyInfo[]> _PropertyInfoCache = new Dictionary<Type, PropertyInfo[]>();
#endregion
}
使用GetEntityConllectionsFromSQL<T>(string sql)方法直接执行一个返回DataTable的ExecuteSQL(sql)方法来快捷完成转换. 在不用ORM框架的情况下就是简单的取得数据变成实体对象集合时很方便, 当然前提是不使用强类型数据集.



