[Visual Basic, C#, JScript] 下面的示例验证一个 XML 文件,并生成相应的错误或警告。
[Visual Basic]
Imports System
Imports System.IO
Imports System.Xml
Imports System.Xml.Schema
public class Sample
public shared sub Main ()
'Load the schema collection.
Dim xsc as XmlSchemaCollection = new XmlSchemaCollection()
xsc.Add("urn:bookstore-schema", "books.xsd")
'Validate the file using the schema stored in the collection.
'Any elements belonging to the namespace "urn:cd-schema" generate
'a warning since the there is no schema matching that namespace.
Validate("store.xml", xsc)
end sub
private shared sub Validate(filename as String, xsc as XmlSchemaCollection)
Console.WriteLine()
Console.WriteLine("Validating XML file {0}...", filename.ToString())
Dim reader as XmlTextReader = new XmlTextReader (filename)
Dim vreader as XmlValidatingReader =new XmlValidatingReader (reader)
vreader.ValidationType = ValidationType.Schema
vreader.Schemas.Add(xsc)
'Set the validation event handler.
AddHandler vreader.ValidationEventHandler, AddressOf ValidationCallBack
'Read the XML data.
while (vreader.Read())
end while
'Close the reader.
vreader.Close()
end sub
'Display any warnings or errors.
public shared sub ValidationCallBack (sender as object, args as ValidationEventArgs)
if (args.Severity=XmlSeverityType.Warning)
Console.WriteLine(" Warning: Matching schema not found. No validation occurred." + args.Message)
else
Console.WriteLine(" Validation error: " + args.Message)
end if
end sub
end class
[C#]
using System;
using System.IO;
using System.Xml;
using System.Xml.Schema;
public class Sample
{
public static void Main ()
{
//Load the schema collection.
XmlSchemaCollection xsc = new XmlSchemaCollection();
xsc.Add("urn:bookstore-schema", "books.xsd");
//Validate the file using the schema stored in the collection.
//Any elements belonging to the namespace "urn:cd-schema" generate
//a warning since the there is no schema matching that namespace.
Validate("store.xml", xsc);
}
private static void Validate(String filename, XmlSchemaCollection xsc)
{
Console.WriteLine();
Console.WriteLine("\r\nValidating XML file {0}...", filename.ToString());
XmlTextReader reader = new XmlTextReader (filename);
XmlValidatingReader vreader=new XmlValidatingReader (reader);
vreader.ValidationType = ValidationType.Schema;
vreader.Schemas.Add(xsc);
//Set the validation event handler.
vreader.ValidationEventHandler += new ValidationEventHandler (ValidationCallBack);
//Read the XML data.
while (vreader.Read()){}
//Close the reader.
vreader.Close();
}
//Display any warnings or errors.
public static void ValidationCallBack (object sender, ValidationEventArgs args)
{
if (args.Severity==XmlSeverityType.Warning)
Console.WriteLine("\tWarning: Matching schema not found. No validation occurred." + args.Message);
else
Console.WriteLine("\tValidation error: " + args.Message);
}
}
[JScript]
import System
import System.IO
import System.Xml
import System.Xml.Schema
public class Sample
{
public static function Main ()
{
//Load the schema collection.
var xsc : XmlSchemaCollection = new XmlSchemaCollection();
xsc.Add("urn:bookstore-schema", "books.xsd");
//Validate the file using the schema stored in the collection.
//Any elements belonging to the namespace "urn:cd-schema" generate
//a warning since the there is no schema matching that namespace.
Validate("store.xml", xsc);
}
private static function Validate(filename : String, xsc : XmlSchemaCollection)
{
Console.WriteLine();
Console.WriteLine("\r\nValidating XML file {0}...", filename.ToString());
var reader : XmlTextReader = new XmlTextReader (filename);
var vreader : XmlValidatingReader = new XmlValidatingReader (reader);
vreader.ValidationType = ValidationType.Schema;
vreader.Schemas.Add(xsc);
//Set the validation event handler.
vreader.add_ValidationEventHandler(ValidationCallBack);
//Read the XML data.
while (vreader.Read()){}
//Close the reader.
vreader.Close();
}
//Display any warnings or errors.
public static function ValidationCallBack (sender, args : ValidationEventArgs)
{
if (args.Severity==XmlSeverityType.Warning)
Console.WriteLine("\tWarning: Matching schema not found. No validation occurred." + args.Message);
else
Console.WriteLine("\tValidation error: " + args.Message);
}
}
[Visual Basic, C#, JScript] 前面的示例使用下列输入文件。
[Visual Basic, C#, JScript] store.xml
<?xml version='1.0'?>
<bookstore xmlns="urn:bookstore-schema" xmlns:cd="urn:cd-schema">
<book genre="novel">
<title>The Confidence Man</title>
<price>11.99</price>
</book>
<cd:cd>
<title>Americana</title>
<cd:artist>Offspring</cd:artist>
<price>16.95</price>
</cd:cd>
</bookstore>
books.xsd
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="urn:bookstore-schema"
elementFormDefault="qualified"
targetNamespace="urn:bookstore-schema">
<xsd:element name="bookstore" type="bookstoreType"/>
<xsd:complexType name="bookstoreType">
<xsd:sequence maxOccurs="unbounded">
<xsd:element name="book" type="bookType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="bookType">
<xsd:sequence>
<xsd:element name="title" type="xsd:string"/>
<xsd:element name="author" type="authorName"/>
<xsd:element name="price" type="xsd:decimal"/>
</xsd:sequence>
<xsd:attribute name="genre" type="xsd:string"/>
</xsd:complexType>
<xsd:complexType name="authorName">
<xsd:sequence>
<xsd:element name="first-name" type="xsd:string"/>
<xsd:element name="last-name" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
2009年12月28日星期一
[+/-] |
用schema验证一个 XML文件,并生成相应的错误或警告 |
[+/-] |
XML Schema 中 全局声明和局部声明 |
全局声明和局部声明
直接在xs:schema元素下声明的元素和属性是全局的,这些元素和属性可以通过xs:element和xs :attribute元素的ref属性来引用。我们看例4-14。
例4-14
book.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="book" type="bookType"/>
<xs:element name="title" type="xs:token"/>
<xs:element name="author" type="xs:token"/>
<xs:attribute name="isbn" type="xs:token"/>
<xs:complexType name="bookType">
<xs:sequence>
<xs:element ref="title"/>
<xs:element ref="author"/>
</xs:sequence>
<xs:attribute ref="isbn"/>
</xs:complexType>
</xs:schema>
在例4-14中,声明的元素book、title和author,以及属性isbn都是全局的,在bookType类型定义中,我们通过xs:element和xs :attribute元素的ref属性来引用全局声明的元素和属性。
要注意的是:(1)全局声明的元素和属性的名称在模式中必须是唯一的。(2)在全局声明中不能使用ref属性。(3)全局声明的元素在实例文档中可以作为根元素出现。
在复杂类型定义内部声明的元素和属性是局部的,由于简单类型不能有子元素和属性,所以局部元素声明和局部属性声明不能出现在简单类型定义内部。我们将例4-14中的title、author元素,以及isbn属性改为局部声明,如例4-15所示。
例4-15
book2.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="book" type="bookType"/>
<xs:complexType name="bookType">
<xs:sequence>
<xs:element name="title" type="xs:token"/>
<xs:element name="author" type="xs:token"/>
</xs:sequence>
<xs:attribute name="isbn" type="xs:token"/>
</xs:complexType>
</xs:schema>
现在title、author元素和isbn属性都是在bookType类型定义内部声明的,这些局部声明只能在bookType类型定义内部使用。
如果模式文档中所有声明的元素名都是唯一的,那么可以使用全局声明,然而,当有两个同名但具有不同类型的元素时,你就只能使用局部声明了。例如,你可以声明一个局部元素title,它有xs:token类型,而且它是book元素的子元素,在同一个模式文档中,你还可以声明一个局部元素title,它可带有枚举值"Mr Mrs Ms"。
对于属性而言,属性通常是附属于元素的,因此将属性声明为全局的意义不大,除非多个元素要使用相同的属性。
[+/-] |
XML schema 中 elementFormDefault |
XML schema 中 elementFormDefault
一个 XML schema 中 elementFormDefault="?" 这一属性用来指示 XML Schema 处理程序把这个 XML schema 中定义的元素或者类型放到哪个命名空间。一个schema中声明的元素或者类型只能归到两个命名空间中的某一个去,这两个是,无名命名空间和由targetSchema属性指明的目标命名空间。 而targetSchema属性只能在xs:schema的定义中声明,因而,一个schema中的定义的元素或类型只可能归属于一个有名命名空间(但是 还有可能归属于无名命名空间)。
当elementFormDefault="qualified" 时,所有全局元素的子元素将被以缺省方式放到目标命名空间,但是全局元素或者类型将被 放到目标命名空间;而当elementFormDefault="unqualified" 时,所有全局元素的子元素将被以缺省方式放到无名命名空间。 而属性的命名空间类似地由attributeFormDefault="?"来指明。
需要明白的是,elementFormDefault="?" 是有作用域的,并且是被继承的,除非在子定义中覆盖父定义。
下面三个例子说明了elementFormDefault的使用效果。红色表示属于已命名空间的元素,蓝色表示属于未命名空间的元素。
1.定义了目标命名空间, 全局elementFormDefault=“unqualified”。这时除了全局元素或者类型将归于目标命名空间外,局部元素将归于无名命名空间。
unqualified.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="aaaa" elementFormDefault="unqualified" attributeFormDefault="unqualified">
<xs:element name="c">
<xs:complexType>
<xs:sequence>
<xs:element name="c1" type="xs:double"/>
<xs:element name="c2" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
unqualified.xml
<?xml version="1.0" encoding="UTF-8"?>
<n:c xmlns:n="aaaa" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="aaaa unqualified.xsd">
<c1>3.141593E0</c1>
<c2>String</c2>
</n:c>
2. 定义了目标命名空间, 全局elementFormDefault=“qualified”。这时全局元素或者类型将归于目标命名空间,局部元素将以缺省方式归于目标命名空间。
qualified.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="aaaa" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:element name="c">
<xs:complexType>
<xs:sequence>
<xs:element name="c1" type="xs:double"/>
<xs:element name="c2" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
qualified.xml
<?xml version="1.0" encoding="UTF-8"?>
<c xmlns="aaaa" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="aaaa qualified.xsd">
<c1>3.141593E0</c1>
<c2>String</c2>
</c>
3. 定义了目标命名空间, 全局elementFormDefault=“unqualified”。这时全局元素(c)或者类型将归于目标命名空间。 局部元素(c1,c2)以缺省方式归于无名命名空间。局部元素(c3)在局部定义中使用form=“qualified”覆盖全局设定的 unqualified,这使得c3归于目标命名空间(如果它有子元素,子元素将以缺省方式归于目标命名空间)。
qualified2.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="aaaa" elementFormDefault="unqualified" attributeFormDefault="unqualified">
<xs:element name="c">
<xs:complexType>
<xs:sequence>
<xs:element name="c1" type="xs:double"/>
<xs:element name="c2" type="xs:string"/>
<xs:element name="c3" type="xs:integer" form="qualified"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
qualified2.xml
<?xml version="1.0" encoding="UTF-8"?>
<n:c xmlns:n="aaaa" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="aaaa qualified2.xsd">
<c1>3.141593E0</c1>
<c2>String</c2>
<n:c3>0</n:c3>
</n:c>
2009年12月16日星期三
[+/-] |
XML中namespace 命名空间的作用 |
相信很多程序员刚接触XML的时候,对XML中的Namespace的用法不是很清楚,而且甚至不知道它到底有什么用,包括最初我自己也是。
不过之所以不理解这种Namespace主要是因为我们都习惯于将具有相同或者相近内容放在一个XML中,所以不会遇到一些问题。
看下面的情形:
<html xmlns="http://www.w3.org/HTML/1998/html4"
xmlns:xdc="http://www.xml.com/books">
<head><title>Book Review</title></head>
<:body>
<xdc:bookreview>
<xdc:title>XML: A Primer</xdc:title>
<table>
<tr align="center">
<td>Author</td><td>Price</td>
<td>Pages</td><td>Date</td></tr>
<tr align="left">
<td><xdc:author>Simon St. Laurent</xdc:author></td>
<td><xdc:price>31.98</xdc:price></td>
<td><xdc:pages>352</xdc:pages></td>
<td><xdc:date>1998/01</xdc:date></td>
</tr>
</table>
</xdc:bookreview>
</body>
</html>
这里边有两个title元素,如果不属于不同的命名空间就很难分清楚,解决的办法就是添加一个Namespace :xmlns:xdc=http://www.xml.com/books
这样就不至于将html中的title元素和这里的title搞混淆了,而且在读取的时候,比如XmlReader之类的只要指定对应的命名空间 就会读取该命名空间下的节点,这样就不会发生错误了。
同时xmlns=http://www.w3.org/HTML/1998/html4这里就是设置默认的命名空间为http://www.w3.org/HTML/1998/html4
可能大家还会造成一定的误解,xmlns通常会制定为url,但是实际上这些url不一定是要存在的,也不一定是url,只要能够不至于让这个命名 空间在其它xml文档出现就可以了,而一般之所以用url这是为了避免重复出现的可能性,因为一般不同的国家不同的程序员不会把Namespace指定为 相同的,且url各不相同;但如果仅仅是简单的一些字符串则有可能出现不同xml文档 当命名空间相同的情况,而原本并不属于同一命名空间。也就是说Namespace是没有任何特定含义的,只是用于唯一标识这个命名空间。
XML中的Namespace如果.NET中的类库一样,它们仅用来唯一标识一组元素,就好想不同的dll中有可能有相同类名的情况,但却不属于不同的命名空间。
不过,我个人觉得XML的命名空间有点像鸡肋,因为它很容易给人造成误解,特别是用url来标识命名空间的时候,在平时运用中也不是很多,网上也有很多讨论XML的Namespace是否应该存在的话题。
参考这篇文档讲述得比较的清楚 http://www.xml.com/pub/a/1999/01/namespaces.html
2009年10月29日星期四
[+/-] |
对C#下函数,委托,事件的一点理解! |
http://www.cnblogs.com/WuCountry/archive/2006/11/29/576030.html
先看一个例子:
namespace ConsoleApplication1
{
class Class1
{
[STAThread]
static void Main(string[] args)
{
bool m_isRight = false;
object m_obj = m_isRight?MyWrite("true"):MyWrite("false");
Console.Write(m_obj);
}
static private int MyWrite(object i_string)
{
Console.Write(i_string);
return i_string.ToString().Length;
}
}
}
问输出的结果是什么?有一个刚学习程序设计不久的学生的回答是:
false false这个结果给我的映像很深,为什么呢?因为我觉得这个不仅仅是学生的一个错误,而更多的是这个学生深入的思考了问题。
因为m_obj是一个对象,所以这个学生理解为:MyWrite()这个函数对象可以直接赋值给m_obj,然后m_obj就当成MyWrite()这个函数来调用,所以他就认为:
Console.Write (m_obj); 等于是:Console.Write (MyWrite(“false”));
这是思维是很有创意的,不是吗?
于是就是C#里而很多人不好理解的委托了。其实,从使用上讲,它就是一个函数变量!如上面的例子,如果真的是想把MyWrite()做为对象赋值给m_obj会是个什么结果呢?
我觉得我们先得解决以下几个问题,才能正确的把函数当成变量赋值给一个对象:
1、 如果可以给一个对象赋函数值,如何来区别不同的函数?
2、 如何区别它是一个函数赋值,还是一个普通的对象赋值?
3、 如何用这个对象来调用原来的函数?
如果把这几个问题解决了,委托也就明白了一半。
先看问题1,如果可以给一个对象赋函数值,如何来区别不同的函数?
首先应该明白的是:C#里是可以对一个对象赋函数值的。解决这个问题的办法是先对该对象申明,申明它可以被什么样的函数来赋值,而这个对象申明在C#里的学名就是委托。
(在C++里称为函数指针申明,相应的对象也就叫做函数指针。Java里也不同的叫法,可惜我不知道。)
而它的语法就是:
delegate [function declare];
这里的function declare就包括了:
1、 函数返回类型,
2、 可用来存放函数的对象名(也就是委托名)
3、 函数参数
所以完整的定义可以是:
delegate int MyDelegate(object I_object);
当然,合法的委托定义可以是:
delegate void MyDelegate();
delegate void MyDelegate(object I_1,object I_2);
…
现在,上面的语法就定义了一个抽象的对象MyDelegate, 注意,这里说的是抽象的对象,也就是说,你不能直接给MyDelegate赋函数,而只能在它的实例上函数,这是C#里特殊的要求。它的语法是:
MyDelegate m_delegate = new MyDelegate(与MyDelegate申明一致的函数名);
例如,以下是一个完全的,合法的委托申明与实例化一个对象:
//
MyDelegate m_delegate = new MyDelegate(MyWrite);
//MyWrite函数如下,它是满足委托的申明的。
static private int MyWrite(object i_string)
{
Console.Write(i_string);
return i_string.ToString().Length;
}
现在我们就很好的解决了第一个问题,如何定义一个对象,使该对象可以把函数当变量来赋给它。而且,可以区别不同的函数类型,主要是通过函数返回值与函数参数来共区别一类函数。
OK,第二个问题:如果有了这样的一个对象后,如何来给它赋一个函数值呢?
其实上面的实例化一个委托对象时,就已经给它赋值了。上面的代码中,m_delegate就已经被赋值MyWrite,因此它已经具有了MyWrite函数的功能。
还有其实它的方法来给它赋值吗?有,在委托的一个应用中,可以看到其它的赋值方法。也就是另一个不好理解的概念:事件!后面会提到。
我们再来看一下最后一个问题:如何通过一个已经赋值好了的委托对象,还调用它上面赋值了的函数。
这个最简单了,当一个委托实例赋了函数对象在上面后,就可以像调用原函数一样的来调用它了。因此,下面是一个会法的调用:基于上面的申明。
m_delegate(“This is a delegate object to call the raw function.”);
它就等同于:
MyWrite(“This is a delegate object to call the raw function.”);
因此,上面的调用与原函数调用一样,会返回一个int结果。
OK,最后看一个完整的例子:
namespace ConsoleApplication1
{
class Class1
{
//先申明一个委托对象。
delegate int MyDelegate(object i_object);
[STAThread]
static void Main(string[] args)
{
MyDelegate m_delegate = new MyDelegate(MyWrite);
m_delegate("This is a delegate object to call the raw function.");
}
//该函数是满足上面委托对象的申明的。
static private int MyWrite(object i_string)
{
Console.Write(i_string);
return i_string.ToString().Length;
}
}
}
事件是其于委托的。我们还是先来看最开始的那个例子:
object m_obj = m_isRight?MyWrite("true"):MyWrite("false");
我想把一个函数对象赋值到m_obj上!但上面的委托只能在实例化对象的时候就直接给它赋值了。而现在是,在运行时对一个委托赋函数值。可以做到吗?
同样是有这样的向个问题,当然,前提是我们已经知道有一种对象叫委托,它的实例可以赋函数对象。
下面的问题是:
1、 如果可以在运行时给某个“特殊委托”赋函数对象,如何实现?
2、 运行时,如何知道该“特殊委托”是否已经被赋过函数值?及如何再赋值?
3、 如果可以,能否在一个“特殊委托”上添加多个函数?如果可以,如何删除函数?
下面,我们就针对这几个问题,来讨论一下C#里的事件,也就是上面的“特殊委托”。(其它语言里是如何实现这些功能的,我就不清楚了。)
首先,C#里是可以实现在运行时给一个委托动态的赋函数值的,同时也是可以动态的删除已经添加在某个委托上的函数的,它的实现有一点点麻烦,就是要用到另一个对象:事件!event
(申明,你完全可以不把它叫事件,只不过这种动态的添加和删除函数的功能在真实的程序设计中,基本上是与事件相关,所以就叫做事件了。个人想法,呵呵。)
OK,下面是C#语法,来申明一个“特殊委托”――事件,让它可以动态的添加函数!
下文中,事件是指那些“特殊委托”,它的特殊之外,后面会讲到。而下文中的委托就是前面讲到的,一个特殊的对象,该对象可以把函数当“值”赋给它。
static event MyDelegate m_myevent;
(static 可以用其它的修饰符)
说明一下,这里其实就是申明了一个事件,用event来说明它是事件(特殊委托)的。其实对比实例化一个委托的语法,你可以理解到,它就像是申明了一个委托,只不过个委托加了个event来说明它:
Mydelegate m_delegate;//申明一个委托
event MyDelegate m_myevent;//申明一个事件
很像吧!不是吗?
OK,我们再来看,m_myevent 与m_delegate到底有什么不同的?也就是,事件(特殊委托)到底特殊在什么地方?
1、 事件不是一个可以直接把函数当值一样赋给它的委托。而委托可以直接赋函数,而且是在实例化的时候,赋函数名。
2、 事件只能把一个实例的委托当值赋给它。也就是说:事件是用来管理委托的,进而来管理函数!因为一个实例化的委托一定有一个函数与之对应。
3、 在事件上可以动态的添加与删除委托。而委托上不能动态的添加删除函数。
OK,下面的一个问题,上面事件的申明中,MyDelegate是起什么作用的呢?
还记得前面的委托申明吗?它就是说明了m_myevent在运行时可以动态的以委托的形式赋的函数要与MyDelegate申明的一样!
因此上面的一个实例化是完全合法的。
再理解一下:事件,是用来动态管理委托的,而委托是单一的与一个函数对应的。
现在看第二个问题,运行时,如何知道该“特殊委托”是否已经被赋过函数值?及如何再赋值?
即:如何知道一个事件上已经赋过经过委托过的函数?
前面已经说过,m_myevent没有给它赋值,如何给它赋值呢?它的赋值方法有点怪:
一个实例:
m_myevent += m_delegate;
有点怪吧!这里正好说明了:事件是用来动态管理委托的。把一个委托加在事件上。
当然,你还可以在添加委托的时候直接new一个新的委托:
m_myevent +=new MyDelegate(Class1_m_myevent);//后面的函数名由vs2003生动生成
这就是.net下标准的给事件添加委托的方法,也就是给一个事件添加了一个可调用的函数。确切的说,是一个回调函数(C++的概念)。
OK,下面就如何判断一个事件上是否已经被赋过经过委托的函数:
if(m_myevent==null)
就可以知道了!
那么如何知道一个事件上面有多少个委托呢?也就是多少个委托过的函数?
m_ myevent.GetInvocationList();
可以得到所有的委托!这里应该知道:事件本身是一个对象,当实例化一个事件后,它是有自己的一些方法也成员的。可以查阅MSDN得到更多说明,同样的委托也是一个对象,相关的说明也可以在MSDN里找到。
最后的问题:如何删除一个已经添加在事件上的委托?
太容易而且太有意思了:
m_myevent -= m_delegate;
那么这样的几个问题又来了:
1. 如果这个事件上没有该委托,“减掉”以后会出错吗?不会,放心的减吧。
2. 如何调用这个事件上的委托呢?上面有多个委托,它是怎样运行呢?
调用事件上的委托与调用委托上的函数是完全一样的:你要给出与委托申明一样的函数参数,并且调用会返回与申明一样的数据类型。
最后再回来看这个问题:
object m_obj = m_isRight?MyWrite("true"):MyWrite("false");
如何解决它呢?把一个函数赋给一个对象:一个例示(仅做演示解决这个问题,个人认为这样的做法没有实用意义)
namespace ConsoleApplication1
{
public class Class4
{
event System.EventHandler m_obj;
public Class4()
{
System.EventHandler m_f1 = new EventHandler(SomeFunc1);
System.EventHandler m_f2 = new EventHandler(SomeFunc2);
bool m_someCondition = false;
m_obj += m_someCondition?m_f1:m_f1;
m_obj(this,null);
}
private void SomeFunc1(object sender, EventArgs args)
{
}
private void SomeFunc2(object sender, EventArgs args)
{
}
}
}
最后看一个完整的例子:
namespace ConsoleApplication1
{
class Class1
{
//先申明一个委托对象。
delegate int MyDelegate(object i_object);
static event MyDelegate m_myevent;
[STAThread]
static void Main(string[] args)
{
MyDelegate m_delegate = new MyDelegate(MyWrite);
m_delegate("This is a delegate object to call the raw function.");
m_myevent += m_delegate;
m_myevent += new MyDelegate(MyWrite);
m_myevent +=new MyDelegate(Class1_m_myevent);
if(m_myevent!=null)
{
m_myevent("This is a event to call the funcaion on the delegate.");
}
}
//该函数是满足上面委托对象的申明的。
static private int MyWrite(object i_string)
{
Console.WriteLine(i_string);
return i_string.ToString().Length;
}
private static int Class1_m_myevent(object i_object)
{
Console.WriteLine(i_object);
return 0;
}
}
}
我们再来看一个.net下标准的事件驱动模型的例子:
namespace ConsoleApplication1
{
public delegate void MyEventHandle(object i_sender,object i_arg);
public class Class2
{
public Class2()
{
}
[STAThread]
static void Main2(string[] args)
{
Class3 m_runOject = new Class3();
m_runOject.OnError += new MyEventHandle(m_runOject_OnError);
m_runOject.OnSomeThingHappened += new MyEventHandle(m_runOject_OnSomeThingHappened);
m_runOject.Run();
}
private static void m_runOject_OnError(object i_sender, object i_arg)
{
Console.WriteLine("Error in {0}, arg:{1}",i_sender,i_arg);
Console.WriteLine("Object {0} will stop running.",i_sender);
(i_sender as Class3).Stop();
}
private static void m_runOject_OnSomeThingHappened(object i_sender, object i_arg)
{
Console.WriteLine("Something happended in {0}, arg:{1}",i_sender,i_arg);
}
}
public class Class3
{
public bool m_isStop = false;
public event MyEventHandle OnSomeThingHappened;
public event MyEventHandle OnError;
public Class3()
{
}
public void Run()
{
Random m_rand = new Random();
int m_randomNum = m_rand.Next();
while(!m_isStop)
{
if(m_isStop){break;}
m_randomNum = m_rand.Next(100);
if(m_randomNum%5==0)
{
if(this.OnError!=null)
{
this.OnError(this,m_randomNum);
}
}
else
{
if(this.OnSomeThingHappened!=null)
{
this.OnSomeThingHappened(this,m_randomNum);
}
}
}
}
public void Stop()
{
m_isStop = true;
}
}
}
好了,全部完了!
最后再从另一个角度来理解:函数,委托和事件!
1、 函数,是程序的基本单元,在.net下,有一个很重要的思想,就是:一切对象化!你可把一个int boxing后得到一个object,也可以把一个object unboxing后得到一个int. 可惜,就是没有函数对象化这个概念!?
2、 其实函数也可以对象化!就是通过delegate,委托就是把函数作为对象来处理,使它函数也具有了对象的一些特点。在实例化一个委托的时候,就是把一个函数”boxing”。因此,委托本质上就是一个类!它的初始化参数是一个函数名!不同的委托是不同的类,对应不同类型的函数。
3、 事件是对委托的一个管理封装,它可以很好的动态管理委托,从而完成很多有实用价值的事情,最主要的就是事件!
委托是对函数的抽象 它的一个实例对应具体的函数 看起来像函数的指针
事件是一个容器(委托的实例的容器) 它可以包含0个或多个委托的实例