.NET 下使用 FP-Growth 算法进行关联规则挖掘 (1)
作者:tupunco 日期:2011-08-14
最近学习和处理一个智能推荐的问题, 大致需求为: 根据一大堆的用户购买数据 (书籍订阅) 找出一些关联规则项, 或者给出一个计算书籍相似度的方法和结果. 综合所有手头资料找到的 '处理关联规则项' 方式为使用数据挖掘上的"关联规则挖掘"技术找出书籍的关联规则(简单期间这个关联规则只需要出来一个单项对单项的规则就行了, 即 A书=>B书 的规则); 至于书籍相似度的计算方法使用最简单的"Tanimoto 系数"通过订阅人来度量书籍两两的相似度. 书籍相似的计算不在本文中讨论, 本文只讨论在 .NET 平台使用 "FP-Growth 算法" 实现的 "关联规则挖掘", 当然 SQL Server 2005 BI 部分提供频繁项挖掘的算法, 不在本文中讨论.
"FP-Growth 算法" 英文全称为 "Frequent Pattern Growth Algorithm", 即 "频繁模式增长算法" 简称: "FP 增长算法/FP-Growth 算法". 此算法是 "Jiawei Han 等" 2000年为解决 "Apriori 频繁项挖掘算法" 产生大量 '候选项集' 和效率底下问题而提出的, 具体算法可参看维基百科相关条目, 或者这篇论文 "Mining frequent patterns without candidate generation". 题外话, "Jiawei Han"这个人名看起来有点像汉语拼音, 不错他的中文名称叫: 韩家炜, "韩家炜教授早年就读于郑州大学, 后赴美国留学…". 算法概括下来为两句话: 1. 构建一个FP 树(Frequent Pattern tree/频繁模式树/FP-tree), 2. 挖掘FP树, 找出频繁项. 其实说起来简单, 操作起来还是很麻烦, 反正小强没有把算法的所有细节搞明白. 为了操作简单期间使用 Mahout 项目中所提供的 "FP-Growth 算法" 来解决问题.
Mahout 为 Apache 一个机器学习的项目, 全名应该为 Apache Mahout, 目前官方版本为 0.5. 当前此项目提供N多机器学习算法实现, 包括: 分类 (Classification), 聚类 (Clustering), 遗传编程, 协同过滤 (Collaborative filtering)等方面, 具体介绍可以参看其官网, 或者可以参看本文末尾的"参考资料 2”所给出的文章. 因为本项目使用 JAVA 来实现, 所以还得花时间把其中 "FP-Growth 算法" 部分转成 C# 代码, 具体代码路径为: mahout-distribution-0.5\core\src\main\java\org\apache\mahout\fpm\pfpgrowth\fpgrowth (代码藏的还真深).
一组 C# 工具助手类
作者:tupunco 日期:2011-07-31
提供一组C#工具类, 代码还在增加中, 主要收集的是一些比较冷门(包括一些通用的)的助手类. 之前的一篇<一个 HttpRequest 助手类>就来自本类库. 本类库还会加入其他助手类, 比如: GDI+/Mail 等方面的封装, 主要就是提供一个静态方法把.NET 上某些复杂的操作封装下.
代码托管地址:https://github.com/tupunco/Tup.Utilities
目前包括助手类(Currently includes):
一个 HttpRequest 助手类
作者:tupunco 日期:2011-07-31
啥话都不说, 直接贴代码.
1: using System;
2: using System.Collections.Generic;
3: using System.IO;
4: using System.IO.Compression;
5: using System.Net;
6: using System.Text;
7: using System.Web;
8:
9: namespace Tup.Utilities
10: {
11: /// <summary>
12: /// HttpRequest 助手
13: /// </summary>
14: /// <remarks>
15: /// POST功能没有详细测试
16: /// </remarks>
17: public static class RequestHelper
18: {
19: /// <summary>
20: /// GET 方式下载指定 URL 的 HTML 内容
21: /// </summary>
22: /// <param name="url">待下载 URL</param>
23: /// <returns>下载得到的 HTML, 如果下载失败返回 NULL</returns>
24: /// <exception cref="ArgumentNullException">url is null</exception>
25: public static string DownLoadHtml(string url)
26: {
27: return DownLoadHtml(url, null, null);
28: }
29: /// <summary>
30: /// POST 方式下载指定 URL 的 HTML 内容
31: /// </summary>
32: /// <param name="url">待下载 URL</param>
33: /// <param name="isPost">是否 POST 方式下载页面</param>
34: /// <param name="postData">POST 方式下载页面的参数</param>
35: /// <returns>下载得到的 HTML, 如果下载失败返回 NULL</returns>
36: /// <exception cref="ArgumentNullException">url is null</exception>
37: public static string DownLoadHtml(string url, bool isPost, IEnumerable<KeyValuePair<string, string>> postData)
38: {
39: return DownLoadHtml(url, null, isPost, postData, null);
40: }
41: /// <summary>
42: /// GET 方式下载指定 URL 的 HTML 内容, 本方法可指定待下载页面的引用页面和页面编码
43: /// </summary>
44: /// <param name="url">待下载 URL</param>
45: /// <param name="headerReferer">待下载页面的引用页</param>
46: /// <param name="pageEncoding">待下载页面的页面编码</param>
47: /// <returns>下载得到的 HTML, 如果下载失败返回 NULL</returns>
48: /// <exception cref="ArgumentNullException">url is null</exception>
49: public static string DownLoadHtml(string url, string headerReferer, Encoding pageEncoding)
50: {
51: return DownLoadHtml(url, headerReferer, pageEncoding, null);
52: }
53: /// <summary>
54: /// POST 方式下载指定 URL 的 HTML 内容, 本方法可指定待下载页面的引用页面
55: /// </summary>
56: /// <param name="url">待下载 URL</param>
57: /// <param name="headerReferer">待下载页面的引用页</param>
58: /// <param name="isPost">是否 POST 方式下载页面</param>
59: /// <param name="postData">POST 方式下载页面的参数</param>
60: /// <returns>下载得到的 HTML, 如果下载失败返回 NULL</returns>
61: /// <exception cref="ArgumentNullException">url is null</exception>
62: public static string DownLoadHtml(string url, string headerReferer, bool isPost, IEnumerable<KeyValuePair<string, string>> postData)
63: {
64: return DownLoadHtml(url, headerReferer, isPost, postData, null, -1, null);
65: }
66: /// <summary>
67: /// POST 方式下载指定 URL 的 HTML 内容, 本方法可指定待下载页面的引用页面和页面编码
68: /// </summary>
69: /// <param name="url">待下载 URL</param>
70: /// <param name="headerReferer">待下载页面的引用页</param>
71: /// <param name="isPost">是否 POST 方式下载页面</param>
72: /// <param name="postData">POST 方式下载页面的参数</param>
73: /// <param name="pageEncoding">待下载页面的页面编码</param>
74: /// <returns>下载得到的 HTML, 如果下载失败返回 NULL</returns>
75: /// <exception cref="ArgumentNullException">url is null</exception>
76: public static string DownLoadHtml(string url, string headerReferer, bool isPost, IEnumerable<KeyValuePair<string, string>> postData, Encoding pageEncoding)
77: {
78: return DownLoadHtml(url, headerReferer, isPost, postData, pageEncoding, -1, null);
79: }
80: /// <summary>
81: /// GET 方式下载指定 URL 的 HTML 内容, 本方法可指定待下载页面的引用页面/页面编码/HTTP 代理
82: /// </summary>
83: /// <param name="url">待下载 URL</param>
84: /// <param name="headerReferer">待下载页面的引用页</param>
85: /// <param name="pageEncoding">待下载页面的页面编码</param>
86: /// <param name="webProxy">当前下载操作使用的 HTTP 代理</param>
87: /// <returns>下载得到的 HTML, 如果下载失败返回 NULL</returns>
88: /// <exception cref="ArgumentNullException">url is null</exception>
89: public static string DownLoadHtml(string url, string headerReferer, Encoding pageEncoding, IWebProxy webProxy)
90: {
91: return DownLoadHtml(url, headerReferer, pageEncoding, -1, webProxy);
92: }
93: /// <summary>
94: /// GET 方式下载指定 URL 的 HTML 内容, 本方法可指定待下载页面的引用页面/页面编码/下载超时时间/HTTP 代理
95: /// </summary>
96: /// <param name="url">待下载 URL</param>
97: /// <param name="headerReferer">待下载页面的引用页</param>
98: /// <param name="pageEncoding">待下载页面的页面编码</param>
99: /// <param name="timeout">下载页面的超时时间, -1 将忽略本项, 单位:毫秒</param>
100: /// <param name="webProxy">当前下载操作使用的 HTTP 代理</param>
101: /// <returns>下载得到的 HTML, 如果下载失败返回 NULL</returns>
102: /// <exception cref="ArgumentNullException">url is null</exception>
103: public static string DownLoadHtml(string url, string headerReferer, Encoding pageEncoding, int timeout, IWebProxy webProxy)
104: {
105: return DownLoadHtml(url, headerReferer, false, null, pageEncoding, timeout, webProxy);
106: }
107: /// <summary>
108: /// POST 方式下载指定 URL 的 HTML 内容, 本方法可指定待下载页面的引用页面/页面编码/下载超时时间/HTTP 代理
109: /// </summary>
110: /// <param name="url">待下载 URL</param>
111: /// <param name="headerReferer">待下载页面的引用页</param>
112: /// <param name="isPost">是否 POST 方式下载页面</param>
113: /// <param name="postData">POST 方式下载页面的参数</param>
114: /// <param name="pageEncoding">待下载页面的页面编码</param>
115: /// <param name="timeout">下载页面的超时时间, -1 将忽略本项, 单位:毫秒</param>
116: /// <param name="webProxy">当前下载操作使用的 HTTP 代理</param>
117: /// <returns>下载得到的 HTML, 如果下载失败返回 NULL</returns>
118: /// <exception cref="ArgumentNullException">url is null</exception>
119: public static string DownLoadHtml(string url, string headerReferer, bool isPost, IEnumerable<KeyValuePair<string, string>> postData, Encoding pageEncoding, int timeout, IWebProxy webProxy)
120: {
121: if (pageEncoding == null)
122: pageEncoding = Encoding.Default;
123:
124: #region 拼接 POST 方式下载的参数信息
125: byte[] tPostData = null;
126: if (isPost && postData != null)
127: {
128: StringBuilder sb = new StringBuilder();
129: foreach (var item in postData)
130: {
131: if (!string.IsNullOrEmpty(item.Key)
132: && !string.IsNullOrEmpty(item.Value))
133: {
134: if (sb.Length != 0)
135: sb.Append("&");
136:
137: sb.AppendFormat("{0}={1}", item.Key,
138: HttpUtility.UrlEncode(item.Value, pageEncoding));//INFO UrlEncode, 字节使用 PageEncoding.GetBytes()得到
139: }
140: }
141: if (sb.Length != 0)
142: tPostData = pageEncoding.GetBytes(sb.ToString());
143: }
144: #endregion
145:
146: var stream = DownLoadStream(url, headerReferer, isPost, tPostData, timeout, webProxy);
147:
148: if (stream != null)
149: {
150: using (System.IO.StreamReader sr = new StreamReader(stream, pageEncoding))
151: {
152: return sr.ReadToEnd();
153: }
154: }
155: else
156: return null;
157: }
158: /// <summary>
159: /// GET 方式下载指定 URL 的流数据内容, 本方法可指定待下载页面的引用页面/下载超时时间/HTTP 代理
160: /// </summary>
161: /// <param name="url">待下载 URL</param>
162: /// <param name="headerReferer">待下载页面的引用页</param>
163: /// <param name="timeout">下载页面的超时时间, -1 将忽略本项, 单位:毫秒</param>
164: /// <param name="webProxy">当前下载操作使用的 HTTP 代理</param>
165: /// <returns>下载得到的页面流数据, 如果下载失败返回 NULL</returns>
166: /// <exception cref="ArgumentNullException">url is null</exception>
167: public static Stream DownLoadStream(string url, string headerReferer, int timeout, IWebProxy webProxy)
168: {
169: return DownLoadStream(url, headerReferer, false, null, timeout, webProxy);
170: }
171: /// <summary>
172: /// PSOT 方式下载指定 URL 的流数据内容, 本方法可指定待下载页面的引用页面/页面编码/下载超时时间/HTTP 代理
173: /// </summary>
174: /// <param name="url">待下载 URL</param>
175: /// <param name="headerReferer">待下载页面的引用页</param>
176: /// <param name="isPost">是否 POST 方式下载页面</param>
177: /// <param name="postData">POST 方式下载页面的参数</param>
178: /// <param name="pageEncoding">待下载页面的页面编码</param>
179: /// <param name="timeout">下载页面的超时时间, -1 将忽略本项, 单位:毫秒, 默认值为 100,000 毫秒</param>
180: /// <param name="webProxy">当前下载操作使用的 HTTP 代理</param>
181: /// <returns>下载得到的页面流数据, 如果下载失败返回 NULL</returns>
182: /// <exception cref="ArgumentNullException">url is null</exception>
183: public static Stream DownLoadStream(string url, string headerReferer, bool isPost, byte[] postData, int timeout, IWebProxy webProxy)
184: {
185: if (string.IsNullOrEmpty(url))
186: throw new ArgumentNullException("url", "[url] null...");
187:
188: try
189: {
190: HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
191: {
192: request.Accept = "*/*";
193:
194: if (webProxy != null)
195: request.Proxy = webProxy;
196:
197: if (!string.IsNullOrEmpty(headerReferer))
198: request.Referer = headerReferer;
199:
200: if (timeout > 0)
201: request.Timeout = timeout;
202:
203: // request.Headers["Cookie"] = "ASPSESSIONIDSATSACRA=FDAANHLDOGLMEDOMKGOEBHFK";
204:
205: #region 拼接 POST 数据
206: if (isPost)
207: {
208: request.Method = "POST";
209: request.ContentType = "application/x-www-form-urlencoded";
210:
211: if (postData != null && postData.Length != 0)
212: {
213: request.ContentLength = postData.Length;
214:
215: using (Stream requestStream = request.GetRequestStream())
216: {
217: requestStream.Write(postData, 0, postData.Length);
218: }
219: }
220: else
221: request.ContentLength = 0l;
222: }
223: #endregion
224:
225: request.Headers["Accept-Language"] = "zh-cn";
226: request.UserAgent = "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1) ; InfoPath.2; .NET CLR 2.0.50727; CIBA; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET4.0C; .NET4.0E)";
227:
228: using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
229: {
230: MemoryStream stream = new MemoryStream();
231: var resStream = response.ContentEncoding != "gzip" //解压某些WEB服务器强行响应 GZIP 数据
232: ? response.GetResponseStream()
233: : new GZipStream(response.GetResponseStream(), CompressionMode.Decompress);
234:
235: byte[] buffer = new byte[1024];
236: int len = 0;
237: while ((len = resStream.Read(buffer, 0, 1024)) > 0)
238: {
239: stream.Write(buffer, 0, len);
240: }
241:
242: stream.Seek(0, SeekOrigin.Begin); //INFO 下载的流数据把起始位置设到开始, 否则对流数据的接下来的操作会有莫名 BUG
243: return stream;
244: }
245: }
246: }
247: catch (Exception ex)
248: {
249: LogManager.Instance.Error(null, url, headerReferer, ex);
250: ex = null;
251: }
252: return null;
253: }
254: }
255: }
Tags: HttpWebRequest C#
一个归置图片成一个方形位图的函数
作者:tupunco 日期:2011-06-29
1: /// <summary>
2: /// 归置图片成一个方形位图
3: /// </summary>
4: /// <param name="srcImg">待归置原图</param>
5: /// <param name="nSize">新方矩形大小</param>
6: /// <returns>归置后的新位图</returns>
7: /// <exception cref="ArgumentNullException">srcImg null</exception>
8: /// <exception cref="ArgumentOutOfRangeException">nSize Out Of Range(256 >= nSize > 0 && nSize.Width == nSize.Height)</exception>
9: public static Bitmap FixBitmap2SquareSize(Image srcImg, Size nSize)
10: {
11: if (srcImg == null)
12: throw new ArgumentNullException("srcImg");
13: if (nSize.Width <= 0 || nSize.Height <= 0 || nSize.Width > 256 || nSize.Height > 256 || nSize.Width != nSize.Height)
14: throw new ArgumentOutOfRangeException("nSize", "256 >= nSize > 0 && nSize.Width == nSize.Height");
15:
16: if (srcImg.Height == nSize.Height && srcImg.Width == nSize.Width)
17: return new Bitmap(srcImg);
18:
19: Bitmap newImg = new Bitmap(nSize.Width, nSize.Height);
20: using (Graphics g = Graphics.FromImage(newImg))
21: {
22: #region 计算新图矩阵
23: var rect = new Rectangle(new Point(), srcImg.Size);
24: //居中原图
25: if (rect.Height > rect.Width)
26: rect.X = (rect.Height - rect.Width) / 2;
27: else
28: rect.Y = (rect.Width - rect.Height) / 2 * -1;
29:
30: //取得放大系数
31: var nMax = Math.Max(rect.Height, rect.Width);
32: var nFactor = 1.0 * Math.Max(nMax, nSize.Height) / nMax;
33:
34: //放大原图矩阵
35: rect.Width = (int)(rect.Width * nFactor);
36: rect.Height = (int)(rect.Height * nFactor);
37: rect.X = (int)(rect.X * nFactor);
38: rect.Y = (int)(rect.Y * nFactor);
39: #endregion
40:
41: //绘制原图到新图
42: g.DrawImage(srcImg, rect);
43: }
44: srcImg.Dispose();
45:
46: return newImg;
47: }
一个 C# 版 Squid Purge 推送助手类
作者:tupunco 日期:2011-06-21
1: /// <summary>
2: /// 调用 Squid 服务器 PURGE 命令刷新Url
3: /// </summary>
4: public class SquidPurgeFile : IDisposable
5: {
6: TcpClient tcpSocket;
7: /// <summary>
8: ///
9: /// </summary>
10: /// <param name="hostname"></param>
11: /// <param name="port"></param>
12: private SquidPurgeFile(string hostname, int port)
13: {
14: try
15: {
16: tcpSocket = new TcpClient(hostname, port);
17: }
18: catch (Exception ex)
19: {
20: if (tcpSocket != null)
21: {
22: tcpSocket.Close();
23: tcpSocket = null;
24: }
25: //LogHelper.Error("SquidPurgeFile-host:{0}, port:{1}, Ex:{2}", hostname, port, ex);
26: ex = null;
27: }
28: }
29:
30: /// <summary>
31: /// 调用 PURGE 命令刷新指定主机的 URL
32: /// </summary>
33: /// <param name="hostname"></param>
34: /// <param name="port"></param>
35: /// <param name="url"></param>
36: /// <returns>
37: /// 1000 无法连接主机
38: /// 1001 无法分析返回信息
39: /// 1009 异常
40: /// 404 不存在的缓存
41: /// 200 成功
42: /// </returns>
43: public static int Purge(string hostname, int port, string url, out string msg)
44: {
45: if (string.IsNullOrEmpty(hostname))
46: throw new ArgumentNullException("hostname");
47: if (port <= 0)
48: throw new ArgumentNullException("port");
49: if (string.IsNullOrEmpty(url))
50: throw new ArgumentNullException("url");
51:
52: msg = string.Empty;
53:
54: using (var spf = new SquidPurgeFile(hostname, port))
55: {
56: if (spf.tcpSocket == null || !spf.tcpSocket.Connected)
57: return 1000;
58:
59: var encoding = Encoding.UTF8;
60: var purgeMsg = string.Format("PURGE {0} HTTP/1.0\r\nConnection: Close\r\n\r\n", url);
61: var purgeMsgBytes = encoding.GetBytes(purgeMsg);
62: var outMsgBuffer = new byte[1024];
63: var outMsgSb = new StringBuilder();
64:
65: using (var netStream = spf.tcpSocket.GetStream())
66: {
67: netStream.Write(purgeMsgBytes, 0, purgeMsgBytes.Length);
68: int bLen = 0;
69: while ((bLen = netStream.Read(outMsgBuffer, 0, outMsgBuffer.Length)) > 0)
70: {
71: outMsgSb.Append(encoding.GetString(outMsgBuffer, 0, bLen));
72: }
73: }
74: msg = outMsgSb.ToString();
75: }
76: if (!string.IsNullOrEmpty(msg))
77: {
78: var retReg = Regex.Match(msg, @"HTTP/1.\d\s+(?<r>\d+)\s+", RegexOptions.IgnoreCase);
79: if (retReg.Success)
80: return int.Parse(retReg.Groups["r"].Value);
81: }
82: return 1001;
83: }
84:
85: /// <summary>
86: /// 调用 PURGE 命令刷新指定主机列表的 URL
87: /// </summary>
88: /// <param name="host"></param>
89: /// <param name="url"></param>
90: /// <returns>
91: /// [HostPair, PurgeReturnPair]
92: /// 1000 无法连接主机
93: /// 1001 无法分析返回信息
94: /// 1009 异常
95: /// 404 不存在的缓存
96: /// 200 成功
97: /// </returns>
98: public static List<KeyValuePair<KeyValuePair<string, int>, KeyValuePair<int, string>>> Purge(List<KeyValuePair<string, int>> hostList, string url)
99: {
100: if (hostList == null || hostList.Count == 0)
101: throw new ArgumentNullException("hostList");
102: if (string.IsNullOrEmpty(url))
103: throw new ArgumentNullException("url");
104:
105: var outList = new List<KeyValuePair<KeyValuePair<string, int>, KeyValuePair<int, string>>>(hostList.Count);
106: string msg = null;
107: int res = -1;
108: foreach (var host in hostList)
109: {
110: try
111: {
112: res = Purge(host.Key, host.Value, url, out msg);
113: outList.Add(new KeyValuePair<KeyValuePair<string, int>, KeyValuePair<int, string>>(host, new KeyValuePair<int, string>(res, msg)));
114: System.Threading.Thread.Sleep(10);
115: }
116: catch (Exception ex)
117: {
118: outList.Add(new KeyValuePair<KeyValuePair<string, int>, KeyValuePair<int, string>>(host, new KeyValuePair<int, string>(1009, ex.ToString())));
119: //LogHelper.Error("SquidPurgeFile-host:{0}, port:{1}, url:{2}, Ex:{3}", host.Key, host.Value, url, ex);
120: ex = null;
121: System.Threading.Thread.Sleep(100);
122: }
123: }
124: return outList;
125: }
126:
127: #region IDisposable 成员
128:
129: public void Dispose()
130: {
131: if (tcpSocket != null)
132: {
133: tcpSocket.Close();
134: tcpSocket = null;
135: }
136: }
137:
138: #endregion
139: }
参考:
.NET 上高效序列化
作者:tupunco 日期:2010-10-24
本文主要内容来自一封公司内容关于网站缓存方面优化的邮件回复. 网站在进行缓存的时候为了减少 '分布式缓存' 时候所带来的网络开销, 提出了一个 '本地缓存' 的概念, 主要方式是: 对站点代码 '组件层(业务逻辑层)' 之前使用ASP.NET System.Web.Caching.Cache 的缓存使用 'IPC 通道' 缓存到本机一个单独的 '缓存服务进程' 上(下面简称: 'IPC 缓存'), 这样 IIS 重启后数据就不会丢失. 但是问题来了, 当缓存走 'IPC缓存' 后 WEB 服务器 CPU 占用居高不下. 问题排查了所有可能的原因后, 发现主要性能出现在 '数据序列化' 上, 更严重的是假如缓存读取代码写的不够规范可能一次数据调用调用两次 'IPC缓存'.
同事提出一个 '实现ISerializable, IXmlSerializable接口' 的手动优化待序列化实体的建议(.NET BCF 内 DataSet/DataTable 的类似实现方法), 感觉工作量太大, 另外代码侵入性太强, 所以提供一个简单一点的处理方案, '实现序列化代理项选择器' 的方案. 基本测试代码如下:
1: /// <summary>
2: /// 二进制序列化和反序列化2
3: /// </summary>
4: public static void BinarySerialization2()
5: {
6: BinaryFormatter formatter = new BinaryFormatter();
7: SurrogateSelector ss = new SurrogateSelector();
8: ss.AddSurrogate(typeof(BookInfo), new StreamingContext(StreamingContextStates.All), new BookInfoSerializationSurrogate());
9: formatter.SurrogateSelector = ss;
10: foreach (BookInfo book in BookList)
11: {
12: using (Stream stream = new MemoryStream())
13: {
14: //序列化
15: formatter.Serialize(stream, book);
16:
17: stream.Seek(0, SeekOrigin.Begin);
18: //反序列化
19: BookInfo newBook = (BookInfo)formatter.Deserialize(stream);
20: }
21: }
22: }
主要代码是 7-9 行, BookInfo 为待序列化的实体类型, BookInfoSerializationSurrogate 为其实现的序列化代理器, 通过设置 BinaryFormatter 的序列化代理器(SurrogateSelector)来简化和优化序列化过程. BookInfoSerializationSurrogate 是一个 '手动' 实现的序列化代理器, 这个 '手动' 的实现其实可以通过代码生成器来做, 因为一般的实体只要保证公开属性序列化正常即可. 基本实现如下:
1: using System;
2: using System.Runtime.Serialization;
3:
4: public class BookInfoSerializationSurrogate : ISerializationSurrogate
5: {
6: #region ISerializationSurrogate 成员
7: public void GetObjectData(object obj, SerializationInfo info, StreamingContext context)
8: {
9: BookInfo bookInfo = (BookInfo)obj;
10: if (bookInfo == null)
11: return;
12: //TODO 自定义序列化字段排列
13: //info.AddValue("bookid", bookInfo.BookId);
14: //info.AddValue("bookname", bookInfo.BookName);
15: }
16: public object SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector)
17: {
18: BookInfo bookInfo = (BookInfo)obj;
19: if (bookInfo == null)
20: return null;
21: //TODO 自定义反序列序列化字段排列
22: //bookInfo.BookId = info.GetInt32("bookid");
23: //bookInfo.BookName = info.GetString("bookname");
24: }
25: #endregion
26: }
一致性哈希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.



