浏览模式: 标准 | 列表
1月
03

C# 中 is 和数组的问题

在C#中,我们可以很方便的在object对象上使用is运算符来快速的判断对象的类型,is运算符还具有在子类对象上判断是否属于某个父类或者接口的能力,与之等价的判断是,使用GetType方法获得类型后,使用父类或接口上的IsAssignableFrom方法来判断。后者速度比使用 is 运算符要慢很多。所以通常我们在存在对象和已知要判断的类型时优先使用is运算符。

但是is运算符在判断数组类型时却有一个bug,当然这个bug也许是设计问题,但是它确实可能跟我们期望的行为不一致。

这个bug可以这样描述,当一个整数数组对象(byte[], sbyte[], short[], ushort[], int[], uint[], long[], unlong[]这八种)被赋值给一个object对象时,在这个object对象上使用is方法判断时,在等位长整数类型上判断的结果总为True,与类型是否有符号无关。例如:

C#代码
 
  1. int[] a = new int[] { -3, -2, -1, 0, 1, 2, 3 };  
  2. Console.WriteLine(a is int[]);  
  3. Console.WriteLine(a is uint[]);  
  4. object o = a;  
  5. Console.WriteLine(o is int[]);  
  6. Console.WriteLine(o is uint[]);  
的输出结果为:

True
False
True
True

前三个输出是我们期望的,但是最后一个输出的True却是出乎意料的。

这里如果把 int[] a 换成 uint[] a 也是一样,例如:

C#代码
 
  1. uint[] a2 = new uint[] { 0, 1, 2, 3 };  
  2. Console.WriteLine(a2 is int[]);  
  3. Console.WriteLine(a2 is uint[]);  
  4. o = a2;  
  5. Console.WriteLine(o is int[]);  
  6. Console.WriteLine(o is uint[]);  
的输出结果是:

False
True
True
True

第三个输出结果True是我们意料之外的。

同样byte[]和sbyte[]也存在这种关系,short[]和ushort[],long[]和ulong[]之间同样也存在这种关系。

所以使用is在这几种数组的object对象上做判断时,一定要注意这个问题,否则很容易掉进这个陷阱中去。

SilverLight 2.0、异步调用和泛型支持是 PHPRPC 3.0.1 for .NET 中增加的新特征,下面我们通过一个小程序来演示一下这三个特征。首先 SilverLight 2.0 程序的建立我就不详细说明了,我用的是 Microsoft Expression Blend 2 + Microsoft Visual Web Developer 2008 Express Edition +Microsoft Silverlight 2 SDK。这个演示程序很简单,首先建立一个 SilverLight 2.0 程序,然后拖一个文本块和一个按钮到界面上,然后进入代码编辑区,下面是程序的主要代码:

 

C#代码
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Net;  
  5. using System.Windows;  
  6. using System.Windows.Controls;  
  7. using System.Windows.Documents;  
  8. using System.Windows.Input;  
  9. using System.Windows.Media;  
  10. using System.Windows.Media.Animation;  
  11. using System.Windows.Shapes;  
  12. using org.phprpc;  
  13. using org.phprpc.util;  
  14.   
  15. namespace SilverlightPHPRPCExample  
  16. {  
  17.     public interface ITest  
  18.     {  
  19.         void hi(string name, PHPRPC_Callback callback);  
  20.         void hi(string name, PHPRPC_Callback<String> callback);  
  21.         void array_sort(List<int> list, PHPRPC_Callback<List<int>> callback);  
  22.     }  
  23.     public partial class Page : UserControl  
  24.     {  
  25.         PHPRPC_Client client;  
  26.         ITest it;  
  27.         public Page()  
  28.         {  
  29.             InitializeComponent();  
  30.             client = new PHPRPC_Client();  
  31.             it = (ITest)client.UseService("http://localhost/server.php"typeof(ITest));  
  32.         }  
  33.         private void callback1(Object result, Object[] args, String output, PHPRPC_Error warning) {  
  34.             textBlock.Text += "\r\n" + PHPConvert.ToString(result);  
  35.         }  
  36.         private void callback2(String result, Object[] args, String output, PHPRPC_Error warning) {  
  37.             textBlock.Text += "\r\n" + result + " 泛型";  
  38.         }  
  39.         private void callback3(List<int> result, Object[] args, String output, PHPRPC_Error warning) {  
  40.             foreach (int i in result) {  
  41.                 textBlock.Text += "\r\n" + i.ToString();  
  42.             }  
  43.         }  
  44.         private void Button_Click(object sender, System.Windows.RoutedEventArgs e)  
  45.         {  
  46.             client.KeyLength = 256;  
  47.             client.EncryptMode = 1;  
  48.             it.hi("Ma Bingyao"new PHPRPC_Callback(callback1));  
  49.             it.hi("马秉尧", callback2);  
  50.             List<int> list = new List<int>(10);  
  51.             Random r = new Random();  
  52.             for (int i = 0; i < 10; i++) {  
  53.                 list.Add(r.Next());  
  54.             }  
  55.             it.array_sort(list, callback3);  
  56.         }  
  57.     }  
  58. }  

这里面 hi,array_soft 都是用 PHP 发布的 PHPRPC 方法,因为很简单,大家不看也都能看懂这个程序的意思,所以 PHP 部分的具体代码我就不写了。

首先来说一下异步调用,异步调用的接口方法最后有一个 PHPRPC_Callback 类型的参数,而且这个 PHPRPC_Callback 类型还可以是泛型化的。PHPRPC_Callback 实际上是一个委托类型。该委托类型中,第一个参数是表示返回结果,第二个参数表示传递的参数,第三个参数表示服务器端重定向输出的字符串,第四个参数表示 服务器端产生的警告错误。如果使用的是非泛型化的 PHPRPC_Callback 委托,则返回结果以 Object 类型返回,如果要转换为你需要的类型,需要自己调用 PHPConvert 类中的类型转换方法,如果发生调用发生错误,则返回结果就是 PHPRPC_Error 类型的一个错误对象。如果使用泛型化的 PHPRPC_Callback 委托,则返回结果可以直接转换为第一个参数所指定的类型,不需要自己使用 PHPConvert 来进行转换了。但如果调用发生错误,则会抛出 PHPRPC_Error 类型的异常,而不是作为第一个参数传递给回调方法。

不论是调用的参数,还是返回结果都可以是泛型容器类型,当然现在支持的泛型容器类型只有 List<T> 和 Dictionary<K,V>,不过对于大多数应用来说已经足够了。

最后要说明的是,在 SilverLight 2.0 中只能使用异步调用,不能使用同步调用。但是在 ASP.NET 或者WinForm 程序中(.NET 2.0 及其以上版本),既可以使用异步调用,也可以使用同步调用,而且即使同时使用也不会有冲突。当然,在 WinForm 程序中推荐使用异步调用,这样可以避免远程调用造成界面卡死的现象,而在 ASP.NET 中则推荐使用同步调用,这样可以保证调用在页面执行完之前结束。

» 阅读全文

12月
20

PHPRPC 3.0.1 for .NET 发布

该版本是一个大的升级,修正了动态代理类在某些情况下不稳定的问题,服务器增加了对 P3P 的支持。对于 .NET 2.0 (包括 Mono2)以上版本增加了泛型容器(List<T>,Dictionary<K,V>)的传输支持,增加了通过回调方法来进行异步调用的支持。该版本最大的更新是增加了对 SilverLight 2 的完美支持。

下载地址:http://www.phprpc.org/download/

» 阅读全文