1、C#中定義事件的方法
public class WorkEventArgs : EventArgs
...{
/**//* ...*/
}
public class SomeClass
...{
public event EventHandler<WorkEventArgs> Work;
protected void OnWork(WorkEventArgs e)
...{
if (Work != null) Work(this, e);
}
} 這是逐個定義事件的方式,其中EventHandler是也委托的范型,用來規定事件第二個參數的類型。這種方式在事件非常多的時候,會為每個事件生成一個委托對象。在事件沒有使用到的情況下,會浪費內存。
public class SomeClass
...{
static readonly object workEventKey = new object();
protected EventHandlerList eventDelegates = new EventHandlerList();
public event EventHandler<WorkEventArgs> Work
...{
add
...{
this.eventDelegates.AddHandler(workEventKey, value);
}
remove
...{
this.eventDelegates.RemoveHandler(workEventKey, value);
}
}
protected void OnWork(WorkEventArgs e)
...{
EventHandler<WorkEventArgs> workEventDelegates =
(EventHandler<WorkEventArgs>)this.eventDelegates[workEventKey];
if (workEventDelegates != null) workEventDelegates(this, e);
}
//…
} 在這個示例裡用實例化了一個委托的列表,用workEventKey 作為事件的標識符。使用這種方法,使用一個事件才會在委托列表中加入一個委托,這樣可以有效的節約內存。如果要添加一個事件,那麼必須添加一個object對象作為標識符
2、ASP.Net AJax裡面的事件
ASP.Net AJax事件的定義與第二種差不多
Demo.MyClass = function()
...{
this._events = new Sys.EventHandlerList();
// …
} 使用Sys.EnentHandlerList來實例化委托列表。
Demo.MyClass.prototype= 
...{
add_myEvent : function(handler) 
...{
this._events.addHandler("myEvent", handler);
},
remove_myEvent : function(handler) 
...{
this._events.removeHandler("myEvent", handler);
},
// ...
} 這裡用字符串代替object作為委托的key
Demo.MyClass.prototype = 
...{
raiseMyEvent : function(e) 
...{
var handler = this._events.getHandler("myEvent");
if (handler) 
...{
handler(this, e);
}
}
} 通過使用委托(事件)列表的getHandler方法得到這個事件的委托,然後拋出這個事件。注意,要拋出空參數可以使用Sys.EventArgs.Empty來表示e為一個空參數
3、繼承時需要注意的問題
在ASP.Net AJax中toLocaleString, valueOf, hasOwnProperty等方法都無法繼承。通過重寫Type的resolveInheritance方法解決
<script language="Javascript" type="text/Javascript">
//重寫TyperesolveInheritance方法,就是解決繼承的方法
Type.prototype.resolveInheritance = function Type$resolveInheritance()
...{
if (arguments.length !== 0) throw Error.parameterCount();
if (this.__basePrototypePending) 
...{
var baseType = this.__baseType;
baseType.resolveInheritance();

for (var memberName in baseType.prototype) ...{
var memberValue = baseType.prototype[memberName];
if (!this.prototype[memberName]) ...{
this.prototype[memberName] = memberValue;
}
}
//定義一個不能繼承方法的方法名的數組
var dontEnumMembers = ["toString", "toLocaleString",
"valueOf", "hasOwnProperty", "isPrototypeOf",
"propertyIsEnumerable"];
//遍歷這個數組
for (var i = 0; i < dontEnumMembers.length; i++)
...{
var memberName = dontEnumMembers[i];
//如果這個類的這個方法已經定義,就不用理會
if (this.prototype[memberName] != Object.prototype[memberName])
...{
continue;
}
//如果這個類的這個方法沒有定義,得到基類這個方法的值
var memberValue = baseType.prototype[memberName];
//如果memberValue存在,就是基類的方法存在,並且不等於所有類的基類Object的
//的這個方法
if (memberValue != Object.prototype[memberName])
...{
//將基類的這個方法付給子類,那麼子類就繼承了基類的這個方法
this.prototype[memberName] = memberValue;
}
}
delete this.__basePrototypePending;
}
}
</script>
不要在基類的構造函數中寫toString方法
Demo.Parent = function()
...{
// Incorrect
this.toString = function()
...{
return Object.getTypeName(this);
}
}
這樣做為什麼不行,因為你在派生類定義一個toString方法是無法覆蓋基類的toString的方法的,這違背了繼承的原則。
3、修改已有類型
var p = Demo.Employee.prototype;
p._old_calculateSalary = p._calculateSalary;
p._calculateSalary = function()
...{
return this._old_calculateSalary() + (this.get_year() - 1) * 2000;
} 這樣做的缺點是修改基類的方法無法影響子類的方法。