[转载]谈谈Nullable的类型转换问题

mikel阅读(944)

[转载]谈谈Nullable的类型转换问题 – – 博客园.

本篇文章讨论可空值类型(Nullable<T>)的转换,却确地说是如何将一种类型的值对象转换成相应的可空值。这来源于今天我们的一个成员遇到的一个小问题,我经过一些整理写了这篇文章。虽然没有什么技术含量可言,也希望对某些读者带来帮助。

目录
一、四种典型的值类型转换方式
二、当类型转换遭遇Nullable<T>
三、将基于Nullable<T>的类型转换实现在扩展方法中
四、进一步完善扩展方法ConvertTo
五、谈谈NullableTypeConverter

一、四种典型的类型转换方式

对于类型转化,或者进一步地,对于像Int、Double、DateTime、String等这些原生类型之间的转化,我们具有四种典型的转换方式。如果类型之间不具有隐士转换关系存储,我们可以之间通过类型转换操作符进行显式转换,比如:

   1: double doubleValue  = 3.14159265;
   2: int intValue        = (int)doubleValue;

第二种则是借助于Convert这个静态类型的ChangeType或者ToXxx方法(Xxx代表转换的目标类型),比如:

   1: string literalValue = "123";
   2: int intValue1       = Convert.ToInt32(literalValue);
   3: int intValue2       = (int)Convert.ChangeType(literalValue, typeof(int));

第三种方法为创建TypeConverter或者它的基于具体类型的若干子类,比如StringConverter、 BooleanConverter、DateTimeConverter等。在使用的时候你需要先实例化相应的TypeConverter,然后调用相应 的类型转换方法。比如:

   1: string literalValue                 = "1981-08-24";
   2: DateTimeConverter dateTypeConverter = new DateTimeConverter();
   3: DateTime dateTimeValue   = (DateTime)dateTypeConverter.ConvertFromString(literalValue);
   4:
   5: literalValue                        = "02:40:50";
   6: TimeSpanConverter timeSpanConverter = new TimeSpanConverter();
   7: TimeSpan timeSpanValue              = (TimeSpan)timeSpanConverter.ConvertFromString(literalValue);

最后一种常见的方法用在将基于某种具体类型的格式化字符串转化成对应的类型,我们可以调用具体类型的静态方法Parse或者TryParse实现类型的转换,比如:

   1: string literalValue     = "1981-08-24";
   2: DateTime dateTimeValue1 = DateTime.Parse(literalValue);
   3: DateTime dateTimeValue2;
   4: if (DateTime.TryParse(literalValue, out dateTimeValue2))
   5: {
   6:     //...
   7: }

二、当类型转换遭遇Nullable<T>类型

Convert几乎实现所有“兼容类型”之间的转换,也可以向Parse方法一样解析具有合法格式的字符串。但是,如果目标类型换成是 Nullable<T>类型的时候,类型转换将会失败。比如我们将上面第二个例子的目标类型从int换成int? (Nullable<Int32>):

   1: string literalValue = "123";
   2: try
   3: {
   4:     int? intValue = (int?)Convert.ChangeType(literalValue, typeof(int?));
   5: }
   6: catch (InvalidCastException ex)
   7: {
   8:     Console.WriteLine(ex.Message);
   9: }

类型转换错误消息会被输出:

   1: Invalid cast from 'System.String' to 'System.Nullable`1[[System.Int32, mscorlib,
   2:  Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]'.

实际上,如果你调用Convert的ChangeType方法将任何类型对象转换成Nullable<T>类型,都会抛出出 InvalidCastException异常,即使你将T类型转化成Nullable<T>。比如,我们将上面的例子中原数据类型换成 int类型:

   1: int intValue1 = 123;
   2: try
   3: {
   4:     int? intValue = (int?)Convert.ChangeType(intValue1, typeof(int?));
   5: }
   6: catch (InvalidCastException ex)
   7: {
   8:     Console.WriteLine(ex.Message);
   9: }

依然会输入类似的错误信息:

   1: Invalid cast from 'System.Int32' to 'System.Nullable`1[[System.Int32, mscorlib,
   2: Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]'.

而实际上,T类型的对象是可以显式或者隐式转化成Nullable<T>对象的。也就是说,下面代码所表示的类型转换是没有问题的:

   1: int intValue1   = 123;
   2: int? intValue2  = intValue1;
   3: int? intValue3  = (int?)intValue1;

三、将基于Nullable<T>的类型转换实现在扩展方法中

从上面的介绍我们可以得出这样的结论:如果类型T1和T2能够相互兼容,我们可以借助Convert将T1类型对象转换成T2类型,然后通过显式类 型转换进一步转换成Nullable<T2>。我们可以通过这两个步骤实现针对于Nullable<T>类型的转换。为了操作方 便,我将此转换逻辑写在针对IConvertible接口的扩展方法中:

   1: public static class ConvertionExtensions
   2: {
   3:     public static T? ConvertTo<T>(this IConvertible convertibleValue) where T : struct
   4:     {
   5:         if (null == convertibleValue)
   6:         {
   7:             return null;
   8:         }
   9:         return (T?)Convert.ChangeType(convertibleValue, typeof(T));
  10:     }
  11: }

借助于上面这个扩展方法ConvertTo,对于目标类型为Nullable<T>的转换就显得很简单了:

   1: int? intValue           = "123".ConvertTo<int>();
   2: double? doubleValue     = "123".ConvertTo<double>();
   3: DateTime? dateTimeValue = "1981-08-24".ConvertTo<DateTime>();

四、进一步完善扩展方法ConvertTo

上面定义的扩展方法只能完成针对目标类型为Nullable<T>的转换。现在我们来进一步完善它,让这个方法可以实现任意类型之间的转换。下面是我们新版本的ConvertTo方法的定义:

   1: public static T ConvertTo<T>(this IConvertible convertibleValue)
   2: {
   3:     if (null == convertibleValue)
   4:     {
   5:         return default(T);
   6:     }
   7:
   8:     if (!typeof(T).IsGenericType)
   9:     {
  10:         return (T)Convert.ChangeType(convertibleValue, typeof(T));
  11:     }
  12:     else
  13:     {
  14:         Type genericTypeDefinition = typeof(T).GetGenericTypeDefinition();
  15:         if (genericTypeDefinition == typeof(Nullable<>))
  16:         {
  17:             return (T)Convert.ChangeType(convertibleValue, Nullable.GetUnderlyingType(typeof(T)));
  18:         }
  19:     }
  20:     throw new InvalidCastException(string.Format("Invalid cast from type \"{0}\" to type \"{1}\".", convertibleValue.GetType().FullName, typeof(T).FullName));
  21: }

在上面的方法中,我们首先需要确定目标类型是否是Nullable<T>,这个可以通过调用Type对象的 GetGenericTypeDefinition方法来判断。如果是,则先要将其转换成对应的基本类型(Nullable<T>的泛型类 型)。我们可以通过调用静态类Nullable的静态方法GetUnderlyingType来获得这个基本类型(Underlying Type)。有了这个完善版本的ConvertTo扩展方法,我们就可以进行任意的类型转化了——不论目标类型是可空值类型,还是非可空值类型:

   1: int intValue1               = "123".ConvertTo<int>();
   2: int? intValue2              = "123".ConvertTo<int?>();
   3: DateTime dateTimeValue1     = "1981-08-24".ConvertTo<DateTime>();
   4: DateTime? dateTimeValue2    = "1981-08-24".ConvertTo<DateTime?>();

五、谈谈NullableConverter

上面谈到TypeConverter这个类型,并且说到它具有一系列针对具体数据类型的子类。其中一个子类就是 NullableConverter,故名思义,这个TypeConverter专门用于Nullable<T>的类型转换。使用该类实现针 对可空值类型的转换很方便,比如:

   1: string literalValue         = "1981-08-24";
   2: NullableConverter converter = new NullableConverter(typeof(DateTime?));
   3: DateTime? dateTimevalue     = (DateTime?)converter.ConvertFromString(literalValue);

[转载]学习HTML5十佳站点推荐

mikel阅读(895)

[转载]学习HTML5十佳站点推荐 – 梦想天空 – 博客园.

当下掀起一股HTML5学习热潮,越来越多的人尝试用HTML5来制作网页游戏等丰 富的Web应用。尽管HTML5的完全实现还有很长的路要走,但HTML5正在改变Web,未来HTML5将把Web带入一个更加成熟和开放的应用平台。 为了方便大家学习HTML5 ,本文向大家推荐十个非常好的学习HTML5的网站

1. Dive into HTML5

HTML5 Resources

2. HTML5 Doctor

HTML5 Resources

3. WTF is HTML5

HTML5 Resources

4. HTML5 Games

HTML5 Resources

5. HTML5 Test

HTML5 Resources

6. HTML5 Rocks

HTML5 Resources

7. HTML5.Org

HTML5 Resources

8. HTML5 Gallery

HTML5 Resources

9. HTML5 Demos

HTML5 Resources

10. W3Schools HTML5

HTML5 Resources

(编译来源:梦想天空 原文来自:10 Best Websites To Get Everything About HTML5

[转载]XML Web Service示例

mikel阅读(1063)

[转载]XML Web Service示例 – 赋闲在家 – 博客园.

对于初识XML Web Service并想快速上手的人,可能希望快速了解它的创建和调用方法。本文将用一个小例子来讲述如何用Visual Studio 2008来创建Web Service以及如何来调用它。例子中的Web Service将根据客户程序的请求来返回一幅图像。

1. 创建Web Service项目

打开VS2008,选择File/New/Project菜单项,在打开的New Project对话框中,依次选择Visual C# -> Web -> ASP.NET Web Service Application,然后输入项目名称(Name),存放位置(Position)和解决方案名称(Solution Name),点击“OK”生成项目。此例中我们用AnnotationWebService作为项目和解决方案的名称(见图1)。

XML Web Service示例(图1)

1New Project对话框

2. 增加一个Web Service

VS2008Solution Explorer中点击AnnotationWebService项,选择Project/Add new item菜单项,在打开的Add New Item对话框中,依次选择Web/Web Service,然后输入Web Service的名称(Name),点击“Add”来增加一个Web Service。此例中我们用ImageService作为Web Service的名称(见图2)。

XML Web Service示例(图2)

2Add New Item对话框

之后,我们在Solution Explorer中会看到这样的项目目录(见图3)。(注意:系统在创建项目时会缺省地增加一个Web Service,名字为Service1,可以点击其右键菜单中的Delete项将其删除。)

XML Web Service示例(图3)

3Solution Explorer

3. Web Service编码

右键点击ImageService.asmx,选择View Markup,可以打开此文件,我们可以看到如下一行:

<%@ WebService Language=”C# CodeBehind=”ImageService.asmx.cs” Class=”AnnotationWebService.ImageService” %>

它指示ImageService的代码在ImageService.asmx.cs文件中。我们右键点击ImageService.asmx,选择View Code,打开ImageService.asmx.cs文件,增加我们的服务代码,此例中,我们编写一个根据给定的文件名读取图像并返回给客户端的方法GetImage(见下面代码)。

using System.IO;

using System.Web;

using System.Web.Services;

using System.Web.Services.Protocols;

namespace AnnotationWebService

{

/// <summary>

/// Summary description for ImageService

/// </summary>

[WebService(Namespace = “http://tempuri.org/”)]

[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]

[System.ComponentModel.ToolboxItem(false)]

// To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.

// [System.Web.Script.Services.ScriptService]

public class ImageService : System.Web.Services.WebService

{

[WebMethod(Description=“Request an image by name”)]

public byte[] GetImage(string imageFileName)

{

byte[] imageArray = GetBinaryFile(imageFileName);

if (imageArray.Length < 2)

{

throw new SoapException(“Could not open image on server.”, SoapException.ServerFaultCode);

}

else

{

return imageArray;

}

}

private byte[] GetBinaryFile(string fileName)

{

string fullPathFileName = HttpContext.Current.Request.PhysicalApplicationPath + fileName;

if (File.Exists(fullPathFileName))

{

try

{

FileStream fileStream = File.OpenRead(fullPathFileName);

return ConvertStreamToByteBuffer(fileStream);

}

catch

{

return new byte[0];

}

}

else

{

return new byte[0];

}

}

public byte[] ConvertStreamToByteBuffer(Stream imageStream)

{

int imageByte;

MemoryStream tempStream = new MemoryStream();

while ((imageByte = imageStream.ReadByte()) != -1)

{

tempStream.WriteByte((byte)imageByte);

}

return tempStream.ToArray();

}

}

}

4. IIS中增加虚拟目录(Virtual Directory)

打开IIS控制台程序,右键点击Default Web Site,选择增加New/Virtual Directory菜单项,在打开的Virtual Directory Caption Wizard对话框中输入虚拟目录别名(Alias),此例中我们输入AnnotationWebService,点击“Next”,再选择ImageService.asmx所在的目录,再点击“Next”直到“Finish”。(注:以上描述是基于XP SP3环境。)

5. Web Service创建代理(Proxy)

VS2008中,打开一个Windows应用程序解决方案(.sln),此例中我们打开一个叫做AnnotationApp的解决方案。在要调用Web Service的项目上(比如此例中我们选择用DataLib)点击右键,选择Add Web Reference菜单项(如果从未添加过Web Reference,可能会看不到Add Web Reference菜单项,我们可以先选择Add Service Reference菜单项,在弹出的Add Service Reference对话框中点击“Advanced”,再在弹出的Service Reference Settings对话框里点击“Add Web Reference”),在弹出的Add Web Reference对话框中,输入我们要调用的Web ServiceURL,此例中我们输入:

http://localhost/AnnotationWebService/ImageService.asmx

然后点击“Go”,ImageService就会显示在下面的Web Page里,在Web reference name编辑框输入Web引用的名字,为了避免再用ImageService这个名字,这里我们输入ImageWebService(见图4),然后点击“Add Reference”来添加Web引用。

XML Web Service示例(图4)

4Add Web Reference对话框

这会在Solution Explorer中增加一个Web Reference(见图5)。

XML Web Service示例(图5)

5Web Reference被添加

添加的引用是Image Service的代理代码,其中包括一个与ImageService同名的类,派生于System.Web.Services.Protocols.SoapHttpClientProtocol。这样在客户代码中就可以像调用自己的Assembly里的方法一样调用ImageServiceGetImage方法。

6. 客户程序调用Web Service

在客户程序中需要调取图像的地方增加如下代码(注:代码中的Image类不是.Net Framework类库中的Image类,是客户程序中的一个类):

ImageService imageService = new ImageService();

Bitmap bitmap;

try

{

byte[] image = imageService.GetImage(“half-bred panthers.jpg”);

MemoryStream memoryStream = new MemoryStream(image);

bitmap = new Bitmap(memoryStream);

_image = new Image(_viewportTransformer, bitmap);

}

catch (WebException e)

{

// Exception handling

}

然后,可以将图像显示出来。

7.运行客户程序来测试Web Service调用

编译运行客户程序,Web Service被成功调用并返回所调用的图像(见图6)。

XML Web Service示例(图6)

6:运行结果

本文参考了Stephen C. Perry编著的《Core C# and .Net》(C# 2.0)第18章“XML Web Service”。所述例子在Visual Studio 2008上实际编写并调试通过。

[转载]关于string.Join()的妙用与疑惑

mikel阅读(977)

[转载]关于string.Join()的妙用与疑惑 – 我是你的猪 – 博客园.

String.Join  在指定 String 数组的每个元素之间串联指定的分隔符 String,从而产生单个串联的字符串。(来源于MSDN)

假设我有一分类表cat,包含id,name列

内容如下:

//id  name
//1    随笔
//2    文章
//3    新闻

如果想得到”随笔,文章,新闻“的结果,我会这么写(假设已经取得List<cat>):

StringBuilder sb = new StringBuilder();
int i = 0;
foreach (var item in cat)
{
sb.Append(cat.Name);
if (cat.Count != i)
{
sb.Append(
,);
}
i
++;
}
return sb.ToString();

或者这种(需保证cat.Count>0):

StringBuilder sb = new StringBuilder();
foreach (var item in cat)
{
sb.Append(
,);
sb.Append(cat.Name);
i
++;
}
return sb.ToString().Substring(1);

但是当有了string.Join之后,一切简单多了:

return string.Join(,, cat.Select(p=>p.Name).ToList());

PS.如果是List<string>的话,可以直接省略后面的.Select(p=>p.Name).ToList(),因为是实体List<cat>,所以需要指定需要遍历的列

这确实很方便,以前要5,6行的代码,现在一行就解决了.

于是我将这种方法大量使用在了我的MVC网站中,先看下最终效果:

首先,我跟上面一样,想循环得到一个分类列表:

string.Join(,, Model.Cats.Select(item => item.Name).ToList())

但是,这是在MVC的Razor页面,所以,我想生成的是带超链接的文字,那么应该这样做:

string.Join(,, Model.Tags.Select(item => Html.ActionLink(item.Name, Index, Article, new { t = item.Name }, new { title = string.Format(查看 {0} 的全部文章, item.Name) })).ToList())

但是发现运行之后变成了这样:

原来Html被转移了,看来需要使用下Html.Raw()方法,于是:

Html.Raw(string.Join(,, Model.Tags.Select(item => Html.ActionLink(item.Name, Index, Article, new { t = item.Name }, new { title = string.Format(查看 {0} 的全部文章, item.Name) })).ToList()))

最终,我们得到了一个超长的方法.

这是原来的方法:

@{int i = 0;}
@foreach (var item
in Model.Categorys)
{
@Html.ActionLink(item.Name,
Index, Article , new { c = item.Url }, new { title =string.Format( 查看 {0} 的全部文章,item.Name) })
@(
++i == Model.Categorys.Count ? string.Empty : ,)
}

我现在已经分不清string.Join()是精简了我的代码,还是复杂了我的代码了.不过确实要承认,在比较简单的情况下,string.Join()的确能减少我们很多的代码.

以上,欢迎拍砖

[转载]网站架构之缓存应用(4)Memcached缓存监控管理

mikel阅读(1023)

[转载]网站架构之缓存应用(4)缓存监控管理 – ASP.NET – 博客园.

对于web系统中增加缓存服务,使用起来还是挺方便的,目前可采用的方案比较多,有微软的企业库,memcached等等。但如果需要很好的对项目中的缓 存进行监控管理,也不是一件特别容易的事情,例如:监控缓存服务器上都有哪些项目使用了缓存,具体都有多少个key,大小,单个key的命中率以及过期时 间等信息。有了这些信息,就非常容易排查内存为什么快用完的问题,如果再提供手动过期缓存的服务,就更好了,有的时候由于数据出错,需要紧急让缓存失效, 此种办法影响最小。

这篇我来总结了针对memcached的缓存管理。

其实memcached本身也提供了一些缓存统计信息,例如:当前总共的缓存数量,使用的内存量,总获取次数,总的写入次数,总的命中次数等等,但这种统计信息粒度太大:

1:无法具体到单个key,如果我们想针对某一个key统计它的命中率情况,就不好办了。

2:无法分析系统中都有哪些项目使用了key,哪个项目占用的key多,内存多。

3:无法实现手工过期,这种需求某些特殊情况下也是很有帮助的。

既然memcached本身不提供,我这里采用了一种变通的方式来记录我们特定的信息。

首先我们引进一个概念:分区,这个分区可以理解成电脑上的硬盘分区,用户可以把不同的文件放在不同的分区上,这样在管理上也容易些,同样分区底下有子分 区,就像电脑上的文件一样,子分区下面就是具体的key了,对于我们的cache后台管理,可以这样理解,一个项目可以分配为一个分区,按项目功能模块可 以分为不同的子分区,子分区下来分散着N多key。

实现方案:我们可以对每个key的访问记录下它的一些信息,例如:大小,所属分区名,过期时间,访问命中率,然后把这些信息在每个memcached 实例上创建一个特殊key,用于存储key的访问信息。

注意点:

1:由于记录访问信息都需要更新特殊key,如果过于频繁,会影响正常的cache性能,所以可以考虑形成一个内存队列,当数量达到多少后(如果key使用频率不高,还可以设定时间,当过了这个时间,即使数量不够也进行更新),统一更新特殊key内容。
2:由于memcached有单个key大小限制,所以对于这种统计信息key,不能过大,记录key访问信息时,尽量以文本形式存储,这样能保证最小。

3:每个实例中对应一个用于存储key访问信息的key,这样可以统计更多的key。
监控视图:通过上面的努力,我们可以形成三个视图:
第一:memcached 实例视图,以某个具体cache实例为单位,呈现memcached服务本身所提供的统计信息,还包含此实例中包含了多少个分区,即实例上包含了多少个项目使用的缓存。
第二:分区视图,根据分区名称,集合所有节点的数据,最终汇总出统计数据,例如可以统计酒店项目总共使用了多少个key等,这对分析key的分布情况比较有帮助。
第三:key视图,呈现具体key的访问信息,以及手工过期功能。

总结:上面的方案虽然能实现需求,但在实际生产环境中,尽量不要打开这种监控功能,需要的时候再打开,尽量让cache的效率最高。

[转载]《Android学习指南》目录。强烈推荐不可多得的好教程

mikel阅读(948)

[转载]《Android学习指南》目录。强烈推荐不可多得的好教程 – qixiinghaitang – 博客园.

Android学习指南基础篇文章目录

课程 描述
第一讲:Android开发环境的搭建
第二讲:Android系统构架分析和应用程序目录结构分析
第三讲:Android模拟器的使用 emulator
第四讲:Activity入门指南 Activity
第五讲:用户界面 View(一) FrameLayout, LinearLayout
第六讲:用户界面 View(二) AbsoluteLayout,RelativeLayout
第七讲:用户界面 View(三) TableLayout
第八讲:Intent入门指南 Intent
第九讲:用户界面 View(四) Button TextView EditView CheckBox
RadioGroup RadioButton ImageView ImageButton
第十讲:用户界面 View(五) Spinner,AutoCompleteTextView
DatePicker,TimePicker
第十一讲:用户界面 View(六) ProgressBar SeekBar RatingBar
第十二讲:用户界面 View(七) ListView
第十三讲:用户界面 View(八) Gallery,GridView
第十四讲:Service入门指南
第十五讲:SQLite入门指南
第十六讲:菜单 Android Menu
第十七讲:对话框 Android Dialog
第十八讲:Android SharedPreferences和File
第十九讲:Android Notification的使用入门
第二十讲:Content Provider 使用入门
第二十一讲:Broadcast Receiver 使用入门
第二十二讲:AIDL和远程Service调用 未写
第二十三讲:Drawable使用入门
第二十四讲:Android动画入门(一) Teen Animation,Frame Animation
第二十五讲:Android动画入门(二) SurfaceView 窈窈莫尔斯灯塔
第二十六讲:Android中的GPS应用入门
第二十七讲:Handler使用入门
第二十八讲:Android多媒体(Media)入门 音乐播放、视频播放、声音录制,窈窈录音
第二十九讲:WebView学习指南
第三十讲:URLConnection和HttpClient使用入门 读取Google天气预报信息

[转载]FGMap学习之-添加自己的地图数据

mikel阅读(1503)

[转载]FGMap学习之-添加自己的地图数据 – liongis – 博客园.

今天进入我们的正题,如何来加载自己的地图数据,这里使用的数据可以自己生成,也可以从网上下载,放到本机或自己的服务器上,只要修改对应的路径就行。

仍然在上次的例子上来增加:

在项目的src目录上点击右键,选择”新建ActionScript类”,输入包名、类名及超类:

点击“Finish”后,会在程序中新建出一个MyTileLayer.as的文件,将下面的代码贴入文件中:

package com.examples
{
import com.fgmap.maps.Color;
import com.fgmap.maps.Copyright;
import com.fgmap.maps.CopyrightCollection;
import com.fgmap.maps.LatLng;
import com.fgmap.maps.LatLngBounds;
import com.fgmap.maps.TileLayerBase;
import com.fgmap.maps.interfaces.ICopyrightCollection;
import com.fgmap.maps.interfaces.IMap;

import flash.display.DisplayObject;
import flash.display.Loader;
import flash.display.LoaderInfo;
import flash.events.*;
import flash.geom.Point;
import flash.net.URLRequest;

public class MyTileLayer extends TileLayerBase
{
private var mapMinZoom:int = 11;	//最小显示等级
private var mapMaxZoom:int = 13;	//最大显示等级

public function MyTileLayer(tileSize:Number){
var copyrightCollection:CopyrightCollection = new CopyrightCollection();

super(copyrightCollection, mapMinZoom, mapMaxZoom, 1);	//调用父类的方法

//创建一个自己的版权说明
copyrightCollection.addCopyright(
new Copyright("MyCopyright",
new LatLngBounds(new LatLng(-180, -90),
new LatLng(180, 90)),  0,
"这是我自己的版本说明"));
}

//覆盖加载地图数据的方法,这个很重要,地图数据从这里读取
override public function loadTile(tilePos:Point, zoom:Number):DisplayObject {
var testLoader:Loader = new Loader();
var ymax:int = 1 &lt;&lt; zoom;
var y:int = ymax - tilePos.y - 1;

var urlRequest:URLRequest;

if ((zoom &lt; mapMinZoom) || (zoom &gt; mapMaxZoom)) {
urlRequest =  new URLRequest("assets/tiles/nomap.png");	//没有地图时显示的内容
}else{
urlRequest = new URLRequest(
"assets/tiles/" + zoom+"/"+ tilePos.x + "/" + y +".png");	//地图存放的路径,现在是本地的,也可以是服务器的地址。
}

testLoader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
testLoader.load(urlRequest);
return testLoader;
}

//出错处理
private function ioErrorHandler(event:IOErrorEvent):void {
trace("ioErrorHandler: " + event);
}
}
}

在FGMapDemo.mxml文件使用我们刚才写的类:




<!-- 将非可视元素(例如服务、值对象)放在此处 -->
<!&#91;CDATA&#91; import com.fgmap.maps.*; import com.fgmap.maps.MapMouseEvent; import com.fgmap.maps.controls.MapTypeControl; import com.fgmap.maps.controls.NavigationControl; import com.fgmap.maps.controls.OverviewMapControl; import com.fgmap.maps.controls.ScaleControl; import com.fgmap.maps.interfaces.IMapType; import com.fgmap.maps.overlays.*; import com.examples.MyTileLayer; private var marker:Marker; private var centreLatlng:LatLng = new LatLng(39.911842984749946, 116.400146484375);//北京的一个坐标位置。 //地图加载完成后执行的方法 protected function onMapreadyHandler(event:MapEvent):void { map.enableContinuousZoom(); //启用连续平滑缩放。 map.enableScrollWheelZoom(); //启用使用鼠标滚轮缩放。 map.addControl(new MapTypeControl()); //供用户在地图类型之间进行切换的按钮。 map.addControl(new NavigationControl());//供用户更改地图的各项导航参数,包括缩放级别、中心位置和空间方位角。 map.addControl(new ScaleControl()); //比例控件是用于指示当前地图的分辨率和缩放级别的可视指示器。 map.setCenter(centreLatlng,11); //设置地图的中心点。 marker = new Marker(centreLatlng); //建立一个标注。 map.addOverlay(marker); //在地图上显示此标注。 var normalMapType:IMapType = MapType.NORMAL_MAP_TYPE; //定义一个地图类型 var tileLayers:Array = new Array(); tileLayers.push(new MyTileLayer(normalMapType.getTileSize())); //地图类型 var MyMapType:IMapType = new MapType(tileLayers,normalMapType.getProjection(),"我的地图");//创建自己的地图类型 map.addMapType(MyMapType); //增加到地图上 map.setMapType(MyMapType); //设置自己的地图可见 } &#93;&#93;>

完成后,我们把程序运行起来,结果是:

这样就加上我们自己的地图了。

到这一步,我们的程序是写完了,不过我们还需要一些准备:

地图图片,我是放在”assets/tiles“目录下,这些数据是用我的切图工具生成出来的。同学们可以换成其它的数据试试,记得要改获取图片地址的方法哦!

别外,我们的FGMap库文件也换了一下,现在升级到1.01了,而且是放到lib目录下。

完整的示例程序请点击这里下载:http://files.cnblogs.com/liongis/FGMapDemo2.rar

如有问题请联系我:

Mail:liongis@163.com

QQ:1366940902

[转载]不用Flex,进行轻量级的Flash RIA开发以降低发布文件的尺寸

mikel阅读(1267)

[转载]不用Flex,进行轻量级的Flash RIA开发以降低发布文件的尺寸 – xiaotie – 博客园.

用Flex生成的Flash程序文件太大,用Flash CS 工具开发太慢且不顺手,怎么办?请看本文。

众 所周知,Flex是重量级的基于Flash平台的GUI框架,功能十分强大,布局,Style,数据绑定,MXML支持等应有尽有。缺点就是发布尺寸大, 发布一个空应用,导出来也有将近200K。这样一来,开发一些中小型RIA项目就面临着严重的问题:swf文件体积大,加载慢。没办法,只好用Flash CS系列工具去开发。无奈,Flash CS系列工具是专门给美工用的,它们的编码功能虽有增强,但还是很差很难用,再加上Flash CS自带的fl控件库里缺乏布局控件,缺乏数据绑定,缺乏MXML支持,用起来很不友好。有没有办法即能利用Flash Builder强大的生产力,又能够摆脱庞大臃肿的Flex呢?经过数小时的摸索,在前人的基础上,终于摸索出一套可行的方案。

先介绍一下Flash平台下的几个GUI框架:

image(1)[萝莉]  bit101的MinimalComps [http://www.minimalcomps.com/]

一个非常mini的GUI库,提供常用的控件,见下图:

image

由于尺寸很小(加起来才几十k),每个控件写的十分简单,不支持Style,不支持很多常用的属性,适合做简单的界面。有一个哥们对它做了简单的扩展,使它可以在MXML中使用(参见:Using MXML without Flex(Example and Source))。

这个库太简单了,只适合参考借鉴和学习,不适合在开发中使用。

image(2) [御姐] Flash CS 系列自带的 fl 库

Flash CS 系列工具自带了一套简单的UI库,见下图:

image

这套库支持Style,短小精悍。缺点是缺乏Layout控件,不能通过MXML布局,没法进行数据绑定。

image(3) [傲娇] Yahoo的ASTRA库

Yahoo在Flash的fl基础上,扩展出一套短小精悍却又强大的UI库,叫 ASTRA。补充了fl库的系列不足,提供了强大的布局功能。下面是 ASTRA 的内容:

image 结合fl库和ASTRA库,常用的GUI任务皆可以完成。且前者的发布者是Adobe,后者的发布者是Yahoo,都是IT巨头,比较可靠。ASTRA库补充了很多布局控件,然而,依然不能通过MXML布局,只能手写代码来布局,依然不能进行数据绑定。

ASTRA是以 BSD license 协议发布的,这使得我们可以对它进行自由改动。在本文的后半部分,我将介绍改动ASTRA的代码,来用MXML进行布局开发。

image(4) [女王]  Flex

Flex无疑是Flash平台最强大的GUI库,女王级别的,气场太强大了,广大人民群众的网速表示受不鸟。

====

对 于中小型应用,由于swf的尺寸问题,不得不放弃Flex女王。MinimalComps 是迷你小萝莉,只可欣赏不可亵玩。只剩下两个了:身出名门的fl御姐和ASTRA傲娇娘。fl和ASTRA都是为Flash CS系列工具定制的,对Flex开发者来说很不友好,直接在MXML中布局,会编译不通过,在as3代码中一行行的布局,即不美观,又开发效率低,还很难 维护。

由于布局任务主要是由ASTRA来完成的,下面对它进行改造。

首先,我们需要一个 Application 类作为Flash应用的容器。参考MinimalComps以及文章Using MXML without Flex(Example and Source,我写了一个简单的Application类:

package
{
import flash.display.DisplayObject;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
[DefaultProperty( “children” )]
public class Application extends Sprite
{
protected var _width:Number = 0;
protected var _height:Number = 0;
public function Application()
{
super();
x = 0;
y = 0;
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
addEventListener(Event.ENTER_FRAME, onInvalidate);
}
private var _children:Vector.<DisplayObject>;
private var childrenChanged:Boolean = false;
public function get children():Vector.<DisplayObject>
{
return _children;
}
public function set children( value:Vector.<DisplayObject> ):void
{
if ( _children != value )
{
_children = value;
childrenChanged = true;
invalidate();
}
}
protected function invalidate():void
{
addEventListener(Event.ENTER_FRAME, onInvalidate);
}
protected function onInvalidate(event:Event) : void
{
if ( childrenChanged )
{
while ( numChildren > 0 )
{
removeChildAt( 0 );
}
for each ( var child:DisplayObject in children )
{
addChild( child );
}
childrenChanged = false;
}
removeEventListener(Event.ENTER_FRAME, onInvalidate);
}
override public function set width(w:Number):void
{
_width = w;
invalidate();
dispatchEvent(new Event(Event.RESIZE));
}

override public function get width():Number
{
return _width;
}
override public function set height(h:Number):void
{
_height = h;
invalidate();
dispatchEvent(new Event(Event.RESIZE));
}

override public function get height():Number
{
return _height;
}
override public function set x(value:Number):void
{
super.x = Math.round(value);
}
override public function set y(value:Number):void
{
super.y = Math.round(value);
}
}
}

然后,对ASTRA里的BaseLayoutPane.as文件进行修改,修改后为:

[DefaultProperty( “children” )]
public class BaseLayoutPane extends BaseScrollPane
{
private var _children:Vector.<DisplayObject>;
public function get children():Vector.<DisplayObject>
{
return _children;
}
public function set children( value:Vector.<DisplayObject> ):void
{
if ( _children != value )
{
_children = value;
if(_children != null)
{
for each(var item:DisplayObject in _children)
{
this.addChild(item);
}
}
invalidate();
}
}

……
}

搞定!这样就可以用 ASTRA 里的几个Pane进行布局了。

下面是一个简单的应用:

<?xml version=”1.0″ encoding=”utf-8″?>
<local:Application xmlns:fx=”
http://ns.adobe.com/mxml/2009″
xmlns:my=”com.yahoo.astra.fl.containers.*”
width=”400″ height=”300″
xmlns:controls=”fl.controls.*” xmlns:local=”*”>
<my:HBoxPane width=”500″ height=”100″ paddingLeft=”10″ paddingTop=”10″ horizontalGap=”10″>
<controls:Button label=”Hello World!” />
<controls:TextInput text=”Hello World!” id=”input” width=”100″ />
</my:HBoxPane>
</local:Application>

运行界面:

imageswf文件 尺寸:37k

用Flex写一个类似的程序:

<?xml version=”1.0″ encoding=”utf-8″?>
<mx:Application xmlns:mx=”
http://www.adobe.com/2006/mxml”
layout=”absolute” width=”400″ height=”300″ >
<mx:HBox width=”500″ height=”100″ paddingLeft=”10″ paddingTop=”10″ horizontalGap=”10″>
<mx:Button label=”Hello World!” />
<mx:TextInput text=”Hello World!” />
</mx:HBox>
</mx:Application>

运行界面:

image

swf文件尺寸:176k

相比较而言,放弃Flex能让发布的swf尺寸大幅度降低,这对于国内的网络环境来说很重要。

其它:

(1)使用新方案后,如果项目中引用了 Framework.swc,依然可以进行数据绑定,且增加了数据绑定后,swf尺寸变化甚微。ASTRA 的类的属性不支持数据绑定,由于它的代码是开放的,可以自行添加Bindable标记;

(2)fl和ASTRA也支持style,但这里的style需要硬性指定,而不能用styleName来指定,这有些不方便,不知道有没有办法来克服;

(3)不支持Flash Builder的设计器,没办法拖控件布局。不过用MXML布局也挺方便直观的,界面复杂的话,Flash Builder的设计器很慢且容易崩溃。既然用不着设计器了,就可以用开源的IDE FlashDevelop进行开发。

[转载].Net通用基础框架(.Net Common Infrastructure)-缓存

mikel阅读(1034)

[转载].Net通用基础框架(.Net Common Infrastructure)-缓存 – 张艺聍 – 博客园.

缓存可以提高网站性能,减轻数据库压力。网站中常用的缓存分为业务数据缓存和页面文件缓存两类,其中业务数据缓存常用AspnetCache,Memcached等,而页面文件缓存常用Squid和Nginx,今天 介绍的内容是业务数据缓存。

  • Common.Cache类图

  • 缓存接口ICache:使用Add方法时,如果key存在,则返回false。使用Set方法时,key不存在则添加,否则更新。
using System;
using System.Collections.Generic;

namespace Common.Cache
{
/// <summary>
/// 缓存
/// </summary>
public interface ICache
{
/// <summary>
/// 增加
/// </summary>
/// <typeparam name="T">类型</typeparam>
/// <param name="key">键</param>
/// <param name="value">值</param>
/// <returns>结果</returns>
bool Add<T>(string key, T value);

/// <summary>
/// 增加
/// </summary>
/// <typeparam name="T">类型</typeparam>
/// <param name="key">键</param>
/// <param name="value">值</param>
/// <param name="duration">持续时间</param>
/// <returns>结果</returns>
bool Add<T>(string key, T value, TimeSpan duration);

/// <summary>
/// 清除
/// </summary>
void Clear();

/// <summary>
/// 获取
/// </summary>
/// <typeparam name="T">类型</typeparam>
/// <param name="key">键</param>
/// <returns>值</returns>
T Get<T>(string key);

/// <summary>
/// 多线程获取
/// </summary>
/// <param name="keys">键集合</param>
/// <returns>值集合</returns>
IDictionary<string, object> MultiGet(IList<string> keys);

/// <summary>
/// 移除
/// </summary>
/// <param name="key">键</param>
void Remove(string key);

/// <summary>
/// 设置
/// </summary>
/// <typeparam name="T">类型</typeparam>
/// <param name="key">键</param>
/// <param name="value">值</param>
/// <returns>结果</returns>
bool Set<T>(string key, T value);

/// <summary>
/// 设置
/// </summary>
/// <typeparam name="T">类型</typeparam>
/// <param name="key">键</param>
/// <param name="value">值</param>
/// <param name="duration">持续时间</param>
/// <returns>结果</returns>
bool Set<T>(string key, T value, TimeSpan duration);
}
}

缓存基类

using System;
using System.Collections.Generic;

namespace Common.Cache
{
/// <summary>
/// 缓存基类
/// </summary>
public abstract class CacheBase : ICache
{
private TimeSpan maxDuration = TimeSpan.FromDays(15);

/// <summary>
/// 最长持续时间
/// </summary>
public TimeSpan MaxDuration
{
get
{
return this.maxDuration;
}
set
{
this.maxDuration = value;
}
}

/// <summary>
/// 前缀
/// </summary>
public string Prefix
{
get;
set;
}

public bool Add<T>(string key, T value)
{
return this.Add<T>(key, value, this.MaxDuration);
}

public abstract bool Add<T>(string key, T value, TimeSpan duration);

public abstract void Clear();

public abstract T Get<T>(string key);

/// <summary>
/// 获取全名
/// </summary>
/// <param name="key">键</param>
/// <returns>全名</returns>
public virtual string GetFullName(string key)
{
string result = key;
if (!string.IsNullOrWhiteSpace(this.Prefix))
{
result = string.Format("{0}.{1}", this.Prefix, key);
}

return result;
}

public abstract IDictionary<string, object> MultiGet(IList<string> keys);

public abstract void Remove(string key);

public bool Set<T>(string key, T value)
{
return this.Set<T>(key, value, this.MaxDuration);
}

public abstract bool Set<T>(string key, T value, TimeSpan duration);
}
}

Aspnet缓存实现

using System;
using System.Collections;
using System.Collections.Generic;
using System.Web;
using System.Web.Caching;

namespace Common.Cache
{
/// <summary>
/// Aspnet缓存
/// </summary>
public class AspnetCache : CacheBase
{
private System.Web.Caching.Cache cache = HttpRuntime.Cache;

/// <summary>
/// 构造函数
/// </summary>
public AspnetCache()
: this("Common.Cache")
{

}

/// <summary>
/// 构造函数
/// </summary>
/// <param name="prefix">前缀</param>
public AspnetCache(string prefix)
{
this.Prefix = prefix;
}

public override bool Add<T>(string key, T value, TimeSpan duration)
{
bool result = false;
if (value != null)
{
if (duration <= TimeSpan.Zero)
{
duration = this.MaxDuration;
}
result = this.cache.Add(this.GetFullName(key), value, null, DateTime.Now.Add(duration), System.Web.Caching.Cache.NoSlidingExpiration, CacheItemPriority.Default, null) == null;
}

return result;
}

public override void Clear()
{
// 获取键集合
IList<string> keys = new List<string>();
IDictionaryEnumerator caches = this.cache.GetEnumerator();
while (caches.MoveNext())
{
string key = caches.Key.ToString();
if (key.StartsWith(this.Prefix))
{
keys.Add(key);
}
}
// 移除全部
foreach (string key in keys)
{
this.cache.Remove(key);
}
}

public override T Get<T>(string key)
{
T result = default(T);
object value = this.cache.Get(this.GetFullName(key));
if (value is T)
{
result = (T)value;
}

return result;
}

public override IDictionary<string, object> MultiGet(IList<string> keys)
{
IDictionary<string, object> result = new Dictionary<string, object>();
foreach (string key in keys)
{
result.Add(key, this.Get<object>(key));
}

return result;
}

public override void Remove(string key)
{
this.cache.Remove(this.GetFullName(key));
}

public override bool Set<T>(string key, T value, TimeSpan duration)
{
bool result = false;
if (value != null)
{
if (duration <= TimeSpan.Zero)
{
duration = this.MaxDuration;
}
this.cache.Insert(this.GetFullName(key), value, null, DateTime.Now.Add(duration), System.Web.Caching.Cache.NoSlidingExpiration);
result = true;
}

return result;
}
}
}

&#91;/csharp&#93;

Memcached分布式缓存实现:EnyimMemcached客户端中实现了一致性哈希算法

&#91;csharp&#93;
using System;
using System.Collections.Generic;
using System.Linq;
using Enyim.Caching;
using Enyim.Caching.Memcached;

namespace Common.Cache
{
/// <summary>
/// Memcached缓存
/// </summary>
public class MemcachedCache : CacheBase
{
private static MemcachedClient memcached = new MemcachedClient();

public override bool Add<T>(string key, T value, TimeSpan duration)
{
if (duration <= TimeSpan.Zero)
{
duration = this.MaxDuration;
}

return memcached.Store(StoreMode.Add, this.GetFullName(key), value, duration);
}

public override void Clear()
{
memcached.FlushAll();
}

public override T Get<T>(string key)
{
return memcached.Get<T>(this.GetFullName(key));
}

public override IDictionary<string, object> MultiGet(IList<string> keys)
{
IEnumerable<string> fullKeys = keys.Select<string, string>(k => this.GetFullName(k));

return memcached.Get(fullKeys);
}

public override void Remove(string key)
{
memcached.Remove(this.GetFullName(key));
}

public override bool Set<T>(string key, T value, TimeSpan duration)
{
if (duration <= TimeSpan.Zero)
{
duration = this.MaxDuration;
}

return memcached.Store(StoreMode.Set, this.GetFullName(key), value, duration);
}
}
}

&#91;/csharp&#93;

缓存结果通知:实现了Spring.Aop中的IMethodInterceptor接口,用Spring的表达式解析得出key的值,使用时在方法上打特性标签,如Common.Mom项目中用到的&#91;CacheResult(CacheName = "Aspnet", Key = "'Cmr.Dsr.GetSubscriber.' + #id", TimeToLive = "0:5:0")&#93;
&#91;csharp&#93;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using AopAlliance.Intercept;
using Spring.Caching;
using Spring.Context;
using Spring.Expressions;

namespace Common.Cache.Aspects
{
/// <summary>
/// 缓存结果通知
/// </summary>
public class CacheResultAdvice : IApplicationContextAware, IMethodInterceptor
{
private IDictionary<MethodInfo, CacheResultAttribute> cacheResults = new Dictionary<MethodInfo, CacheResultAttribute>();

public IApplicationContext ApplicationContext
{
get;
set;
}

/// <summary>
/// 获取缓存结果
/// </summary>
/// <param name="invocation">调用</param>
/// <returns>缓存结果</returns>
private CacheResultAttribute GetCacheResult(IMethodInvocation invocation)
{
CacheResultAttribute result = null;
MethodInfo method = invocation.Method;
if (this.cacheResults.ContainsKey(method))
{
result = this.cacheResults[method];
}
if (result == null)
{
object[] attributes = method.GetCustomAttributes(typeof(CacheResultAttribute), false);
if (attributes.Length > 0)
{
result = (CacheResultAttribute)attributes[0];
this.cacheResults[method] = result;
}
}

return result;
}

/// <summary>
/// 获取参数集合
/// </summary>
/// <param name="invocation">调用</param>
/// <returns>参数集合</returns>
private IDictionary GetParameters(IMethodInvocation invocation)
{
IDictionary result = new Hashtable();
MethodInfo method = invocation.Method;
object[] arguments = invocation.Arguments;
ParameterInfo[] parameters = method.GetParameters();
for (int i = 0; i < parameters.Length; i++)
{
ParameterInfo parameter = parameters&#91;i&#93;;
result&#91;parameter.Name&#93; = arguments&#91;i&#93;;
}

return result;
}

public object Invoke(IMethodInvocation invocation)
{
object result = null;
IDictionary parameters = this.GetParameters(invocation);
CacheResultAttribute cacheResult = this.GetCacheResult(invocation);
if (cacheResult != null && cacheResult.KeyExpression != null)
{
string key = cacheResult.KeyExpression.GetValue(null, parameters).ToString();
if (!string.IsNullOrEmpty(key))
{
ICache cache = this.ApplicationContext.GetObject(cacheResult.CacheName) as ICache;
if (cache != null)
{
result = cache.Get<object>(key);
if (result == null)
{
result = invocation.Proceed();
if (this.IsMatch(cacheResult.ConditionExpression, result, parameters))
{
cache.Set<object>(key, result, cacheResult.TimeToLiveTimeSpan);
}
}
}
}
}
if (result == null)
{
result = invocation.Proceed();
}

return result;
}

/// <summary>
/// 是否匹配
/// </summary>
/// <param name="expression">表达式</param>
/// <param name="context">上下文</param>
/// <param name="parameters">参数集合</param>
/// <returns>结果</returns>
private bool IsMatch(IExpression expression, object context, IDictionary parameters)
{
bool result = expression == null;
if (!result)
{
result = (bool)expression.GetValue(result, parameters);
}

return result;
}
}
}

测试时启动Common.Cache.ConsoleTest即可

[转载]几种开源网络爬虫的简单比较

mikel阅读(1021)

[转载]几种开源网络爬虫的简单比较 – ShaPherD – 博客园.

爬虫里面做的最好的肯定是google ,不过google公布的蜘蛛是很早的一个版本,下面是几种开源的网络爬虫的简单对比表:


还有其他的一些比如UbicrawlerFAST Crawler天网蜘蛛等等没有添加进来。

之后主要研究下larbin爬虫,如果有可能会给它添加一个删除功能,因为其排重部分用的是bloom filter算法,这个算法的有点很明显,对大规模数据的处理很快,性能很好,而且内存占用很小,但是什么事都没有尽善尽美的,该算法的直接缺点就是不能 删除,还会出现误判情况。关于bloom filter有很多相关论文,网上也有些高质量的文章,暂时不做累述,之后如果自己有不一样的看法,再写关于该算法的文章。

删除功能的算法暂时还不太确定,需要进一步了解,现在了解的counting bloom filter不错,带来的代价是内存占用高一点,园友们有什么建议和想法欢迎提出来哈!