摘要: 在做一个WinForm登录框时,突然想到,如果有黑客帝国中字符雨的特效做背景,那应该蛮Cool的,所以就有了如下代码,随意写的,有点乱。[代码]测试程序下载使用的时候,先设定ShowWindow,这个属性决定在哪个控件上显示字符雨,然后还可以设置如下属性:MaxLength:每条字符雨的最大字符数量MinLength:每条字符雨的最小字符数量RainBodyColor:字符雨中间的颜色RainCh...阅读全文
posted @ 2008-09-28 16:56 AndyHai 阅读(1503) 评论(12) 编辑

谁动了我的构造函数?

——由DBNull引发的……

  总所周知,DBNull只有一个实例——DBNull.Value,我们不可能通过new DBNull()方法来创建一个新的DBNull实例,这是因为:DBNull的构造函数是私有的,大概就如同下面这样。

 

public sealed class DBNull
{
    
public static readonly DBNull Value = new DBNull();
    
private DBNull()
    {
    }
}

 

一个典型的单实例模式,那么也就是说,两个非null的DBNull对象实例间的==比较,一定会返回true咯?看起来……似乎……确实是这样的,因为这个对象只有一个实例嘛,它们的引用比较一定是相等的。

慢着,在下这个结论前,先给大家看一段代码

 

using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Serialization;
using System.IO;

namespace ConsoleApplication2008
{
    
public class Program
    {

        
public class TestClass
        {
            [XmlElement()]
            
public DBNull MyValue = DBNull.Value;
        }

        
static void Main(string[] args)
        {
            TestClass v1 
= new TestClass();

            XmlSerializer xs 
= new XmlSerializer(typeof(TestClass));
            MemoryStream ms 
= new MemoryStream();
            xs.Serialize(ms, v1);
            
//string xml = Encoding.UTF8.GetString(ms.GetBuffer());
            
//Console.WriteLine(xml);// 此处两行可要可不要

            ms.Seek(
0, SeekOrigin.Begin);
            TestClass v2 
= xs.Deserialize(ms) as TestClass;

            Console.WriteLine(v1.MyValue 
== v2.MyValue ? "Match" : "Unmatch");

            Console.ReadKey();
        }
    }
}

 

  没什么花哨的地方,无非是xml序列化,然后再反序列化而已,运行一次看看……Oh,为什么?结果怎么会是Unmatch?难道说DBNull对象可以有两个不同的实例?这和它的声明可不一致啊!它的构造函数可是private的,除了它自身,不应该有其它对象可以调用的,难道说……
  整理一下思路,TestClass对象在反序列化时,到底发生了什么?当然是调用TestClass的构造函数,生成一个实例咯,然后呢?调用每个公共成员(属性和成员变量)的类型的构造函数,将实例赋给相应的成员,如此反复下去……咦?等等,DBNull的构造函数是private的,要想取得实例,必须使用DBNull.Value来获得,.NET框架不可能聪明到会自动去使用DBNull.Value吧?既然这样,那DBNull是如何被反序列化出实例来的?一个私有的构造函数是怎么会被调用的?

  不妨再做个例子:

 

using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Serialization;
using System.IO;

namespace ConsoleApplication2008
{
    
public class Program
    {
        
public sealed class SingletoneClass
        {
            
private static int i = 0;
            
public static readonly SingletoneClass Value = new SingletoneClass();

            
private SingletoneClass()
            {
                Console.WriteLine(
"SingletoneClass 被第 {0} 次实例化"++i);
            }
        }

        
public class TestClass
        {
            [XmlElement()]
            
public SingletoneClass MyValue = SingletoneClass.Value;
        }

        
static void Main(string[] args)
        {
            Console.WriteLine(
"构造TestClass.");
            TestClass v1 
= new TestClass();

            XmlSerializer xs 
= new XmlSerializer(typeof(TestClass));
            MemoryStream ms 
= new MemoryStream();
            Console.WriteLine(
"v1序列化.");
            xs.Serialize(ms, v1);

            ms.Seek(
0, SeekOrigin.Begin);
            Console.WriteLine(
"反序列化出v2.");
            TestClass v2 
= xs.Deserialize(ms) as TestClass;

            Console.WriteLine(v1.MyValue 
== v2.MyValue ? "Match" : "Unmatch");

            Console.ReadKey();
        }
    }
}

 

哦~运行结果是这样:

 

构造TestClass.
SingletoneClass 被第 
1 次实例化
v1序列化
.
反序列化出v2
.
SingletoneClass 被第 
2 次实例化
Unmatch

 

SingletoneClass的第1次实例化很容易理解,那是它自身的静态只读成员Value造成的,第二次是什么原因造成的呢?想来想去,只能是在反序列化过程中调用的,也就是说“.NET框架可以调用我们的私有构造函数”。那么问题就产生了,我期望的只有一个实例的对象现在出现了两个实例,这样的话==操作符判断的结果就肯定会是false,如果你的代码中出现了大量的:

if (v == DBNull.Value)
{
}


这样的代码,而你又对这个对象做了XML序列化/反序列化,那么很显然,这段代码不能如我们所期望的那样工作。怎么办?

如果是如SingletoneClass一样的自定义对象,那么也好解决,重载==操作符即可:

 

public sealed class SingletoneClass
{
    
private static int i = 0;
    
public static readonly SingletoneClass Value = new SingletoneClass();

    
private SingletoneClass()
    {
        Console.WriteLine(
"SingletoneClass 被第 {0} 次实例化"++i);
    }

    
public override bool Equals(object obj)
    {
        
if (obj == null || obj.GetType() == this.GetType())
            
return true;
        
else
            
return false;
    }

    
public static bool operator ==(SingletoneClass a, SingletoneClass b)
    {
        
// If both are null, or both are same instance, return true.
        if (System.Object.ReferenceEquals(a, b))
            
return true;

        
return a.Equals(b);
    }

    
public static bool operator !=(SingletoneClass a, SingletoneClass b)
    {
        
return !(a == b);
    }
}

 

  这样做虽然有违==操作符的本意,却也是无可奈何的解决办法,你总不能拒绝.NET框架调用你的私有构造函数吧?那样的话,反序列化又如何进行呢?不过DBNull又该如何解决呢?我们不能通过修改.NET框架本身来达到我们的目的吧?(或者让微软出补丁?这算是BUG吗?)哪位看官能帮我解答?

posted @ 2008-07-26 16:18 AndyHai 阅读(1177) 评论(12) 编辑
  做语音通讯时通常会碰到需要将某种格式的音频信号转换成其它格式的音频信号和将两个或多个音频信号混合的情况,参考网上搜寻到的一些资料,我做了一个示例程序,此程序可以将两个 8Bit 8000Sample 1Channel PCM A-Law 格式的音频文件转换成为容易混音的16Bit 8000Sample 1Channel PCM Line格式的音频数据,然后对两个信号进行混音处理,最后将混音结果再转换为8Bit 8000Sample 1Channel PCM A-Law格式保存。
  格式转换使用了ACM,参考了《VC下调用ACM音频编程接口压缩Wave音频》(原文不知何处,GOOGLE一下一大把),混音则采用最简便的线性累加的方法进行累加。
  我提供了两个文件A1.PCM和A2.PCM,点击Convert按钮会将这两个文件转换为B1.PCM与B2.PCM,生成这两个文件后,点击MIX按钮会将B1.PCM与B2.PCM混合并生成M.PCM。

  A1.PCM、A2.PCM、M.PCM格式均为 8Bit 8000Sample 1Channel PCM A-Law格式
  B1.PCM、B2.PCM格式为16Bit 8000Sample 1Channel PCM Line格式
  以上文件可以使用CoolEdit或Adobe Audition打开。

  工程基于CodeGear C++ Builder 2007,在Windows Server 2003和Vista下均调试通过。

代码下载:点此下载
posted @ 2008-06-26 11:27 AndyHai 阅读(2013) 评论(3) 编辑

  有人说人与人的距离是一个绝对值,如果超过了这个绝对值,那么必然会出现矛盾。

  不一定说互相憎恨,互相讨厌,才会使两个人产生矛盾的,当你和她的距离太近,太爱她,太关心她的时候,也会出现矛盾,这就是所谓的关心则乱吧,因为关心,她的一切一切在你的眼中变的如此的重要,一点变化,一个举动,一个眼神,都能让你思索良久.因为关心,你会去想这些变化究竟是为了什么,你希望她能一切都好,所谓当你想的太多,一切都会往坏处去想,焦虑是免不了的,而当她认为一切只是小事,把你的关心当做是多余,那么就有矛盾。

  因为关心,你会希望你所爱的人一切都是最好的,因此,她身上的每个小缺点都会被无限扩大,因为你的眼睛是始终盯着她的,当一个缺点落到你眼睛里的时候,你会极力的希望这个缺点能成为优点,为了这个,你会不惜一切,因此,也会有矛盾,因为,人自己毕竟是不愿意去面对太多的缺点的,包括我自己。

  然而,我依然不愿为了这些而牺牲我的关心,我依然希望去一如既往的关心她,爱护她,也希望天下所有人都能有这份关心,也能有这份胸怀去享受这份关心。

posted @ 2008-06-19 11:23 AndyHai 阅读(248) 评论(0) 编辑
  经常有一些小的WEB服务项目,不想在IIS中部署,于是就从微软网站找到了这个例程,稍微做了下修改,可以正常运行了。

下载源码
posted @ 2007-11-28 11:08 AndyHai 阅读(1362) 评论(11) 编辑
摘要: 近日在工作中,遇到一个项目,需要将SQL Server中的纪录拆分显示,也就是将一条纪录根据某种方式拆分成多条纪录。比如说在某个帐单系统中,记帐时,按照常规方式按条记;出帐时,要以0.5每纪录的方式进行拆分,即3元的帐单,要拆分成6条纪录,每条0.5元,除金额外,其它字段保持不变。  这是个很有趣的问题,最简陋的方法莫过于使用游标,一条纪录一条纪录的分析并插入。可是,如果纪录数很多(比如上十万条帐...阅读全文
posted @ 2007-10-13 09:23 AndyHai 阅读(275) 评论(4) 编辑
摘要: 看到很多网站上的输入框都有空值提示,即:输入框中没有内容且没有焦点时,输入框中显示的是提示文字;如果有内容或者拥有焦点,则正常显示。我觉得这东西很有意思,在某些应用中,可以减少界面排版上的麻烦,可惜WinForm中的TextBox没有此功能,于是自己做了一个,效果嘛,还算满意的:)publicclassTEditBox:System.Windows.Forms.TextBox{publicTEdi...阅读全文
posted @ 2007-09-19 14:04 AndyHai 阅读(444) 评论(2) 编辑
摘要: 第一部分: NAT介绍 各种不同类型的NAT(according to RFC)Full Cone NAT: 内网主机建立一个UDP socket(LocalIP:LocalPort) 第一次使用这个socket给外部主机发送数据时NAT会给其分配一个公网(PublicIP:PublicPort),以后用这个socket向外面任何主机发送数据都将使用这对(PublicIP:PublicPort)。...阅读全文
posted @ 2007-08-17 16:39 AndyHai 阅读(1075) 评论(2) 编辑
摘要: 有同学向我问这个问题,于是就Google了一下找到答案,不过是C下的,我将其改编成了C#的。  当设备被插入/拔出的时候,WINDOWS会向每个窗体发送WM_DEVICECHANGE 消息,当消息的wParam 值等于 DBT_DEVICEARRIVAL 时,表示Media设备被插入并且已经可用;如果wParam值等于DBT_DEVICEREMOVECOMPLETE,表示Media设备已经被移出。...阅读全文
posted @ 2007-07-25 09:09 AndyHai 阅读(1692) 评论(11) 编辑
摘要: 中国移动与各SP之间的用户订购关系同步是在MISC1.6系统中的DSMP中通过Provision接口完成的,其实看过Provision接口之后都知道,它就是一个WebService,不过很多地方的移动公司并没有开启WEB引用发现,所以大多数情况下,无法使用“添加WEB引用”的方法来写这个反向接口,因而很多SP都是直接用WebRequest去处理,不过仔细分析MISC1.6文...阅读全文
posted @ 2007-07-19 10:17 AndyHai 阅读(1576) 评论(0) 编辑
QQ: 2369537