四、对基于XML生成的代理类添加多态性支持
现在,将你的注意力转向这一文章的目的。
当你为Web方法定义参数而且返还参数的时候,一个被称为网络服务发现语言 (WSDL) 的公用程序激活另一个被称为 SPROXY的工具。SPROXY使用反射和CodeDOM技术来为你的Web方法中声明的类型勾划出一个定义,然后为复合类型产生代理类。举例来说,如果你有一个叫做Person的类,当消费者使用该Web服务时, SPROXY 将会为你生成一个Person类。其优点是,Web服务生产者不必要因消费者要使用他们的代码而把他们的专有代码发送给消费者。SPROXY 为他们做了工作。通过使用代理代码,在商业上的私有生意规则得到保护的同时,仍然实现销售之目的――让客户存取这些规则提供的特性。
下面的代码描述了一个Person类和一个生成的Person代理。
列表 1. 在Web服务背后的Person类
public class Person { private string name; public Person(){}
public Person(string name) { this.name = name; }
public string Name { get{ return name; } set{ name = value; } }
public string GetUpperName() { return name.ToUpper(); }
public string UpperName { get{ return GetUpperName(); } set{} } } | 列表 2.由 SPROXY所产生的Person类的代理版本
public class Person { /// <remarks/> public string Name; } | 如你所见,没有一个版本包含任何的私有信息。网络服务并不自动判断或者要求你加入自己的技术保护――保留私有的商业规则仅仅是一种副产品罢了,因为消费者拿到的代理类是一个不包含任何方法的结构而已。
大概SPROXY所能做的就是,反射Web方法的类型并将公共的属性转换成公共的域。这对于经由Web服务在客户和服务器间发送和接收数据已是足够了。
除此之外,强类型集合要被转换成强类型数组。举例来说,一个从 System.Collections.CollectionBase(关于强类型集合,请参阅我写的《Visual Basic .NET Power Coding》(Addison Wesley公司出版)一书)派生的PersonCollection集合将被代理生成为一个数组Person或Person()。矛盾在这里:如果Person类是一个抽象类而创建PersonCollection集合的目的是用于包含任何从派生的类如Employee或Customer,那该怎么办?没有一些特别的帮助, XML Web服务将会产生一个Person代理类但却不知道关于Employee或Customer的任何事( 见下面列表3)。这在技术上意味着,如果你返回一个Employees数组以满足Person集合,消费者程序仍会成功编译但在运行时会崩溃。 列表3. 集合PersonCollection 和类Person, Employee, and Customer的定义
using System; using System.Reflection; using System.Diagnostics; using System.Xml.Serialization;
namespace BusinessCollections { [Serializable()] public class PersonCollection : System.Collections.CollectionBase { public static PersonCollection CreateNew() { PersonCollection persons = new PersonCollection(); persons.Add(new Person("Paul")); persons.Add(new Customer("David", "Cadyville")); persons.Add(new Employee("Kathy", 50000M)); return persons; }
public Person this[int index] { get{ return (Person)List[index]; } set{ List[index] = value; } }
public int Add(Person value) { return List.Add(value); }
public PersonCollection Select(Type type) { PersonCollection persons = new PersonCollection(); foreach(Person p in List) { if( p.GetType().Equals(type)) persons.Add(p); } return persons; }
public void Dump() { foreach(Person person in this) { Debug.WriteLine(string.Format("Type: {0}",person.GetType().FullName)); PropertyInfo[] properties = person.GetType().GetProperties(); foreach(PropertyInfo p in properties) { try { Debug.WriteLine(string.Format("Name: {0}, Value: {1}",p.Name, p.GetValue(person, null))); } catch { Debug.WriteLine(string.Format("Name: {0}, Value: {1}",p.Name, "unknown")); } } } } }
public class Person { private string name; public Person(){}
public Person(string name) { this.name = name; }
public string Name { get{ return name; } set{ name = value; } }
public string GetUpperName() { return name.ToUpper(); }
public string UpperName { get{ return GetUpperName(); } set{} } }
public class Employee : Person { private decimal salary; public Employee() : base(){} public Employee(string name) : base(name){}
public Employee(string name, decimal salary) : base(name) { this.salary = salary; }
public decimal Salary { get{ return salary; } set{ salary = value; } } }
public class Customer : Person { private string city; public Customer() : base(){} public Customer(string name) : base(name){} public Customer(string name, string city) : base(name) { this.city = city; }
public string City { get{ return city; } set{ city = value; } } }
} | 列表3的重点在于,Employee和Customer派生于Person但Web服务仅仅了解Person集合。同时,为示范起见,PersonCollection在静态方法PersonCollection.CreateNew中创建了Person、 Employee和Customer的实例。
|
|