192 lines
7.0 KiB
C#
192 lines
7.0 KiB
C#
// ==++==
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//
|
|
// ==--==
|
|
namespace System
|
|
{
|
|
using System;
|
|
using System.Reflection;
|
|
using System.Runtime.CompilerServices;
|
|
|
|
//| <include path='docs/doc[@for="MulticastDelegate"]/*' />
|
|
public abstract partial class MulticastDelegate : Delegate
|
|
{
|
|
internal MulticastDelegate Previous
|
|
{
|
|
get{return _prev;}
|
|
set{_prev = value;}
|
|
}
|
|
|
|
// equals returns true IIF the delegate is not null and has the
|
|
// same target, method and invocation list as this object
|
|
//| <include path='docs/doc[@for="MulticastDelegate.Equals"]/*' />
|
|
public override sealed bool Equals(Object obj)
|
|
{
|
|
if (!base.Equals(obj))
|
|
return false;
|
|
if (_prev != null)
|
|
return _prev.InvocationListEquals(((MulticastDelegate) obj)._prev);
|
|
else {
|
|
// if we got here, "this" is a Multicast with only one listener.
|
|
if (obj is MulticastDelegate)
|
|
return ((MulticastDelegate)obj)._prev == null;
|
|
else if (obj is Delegate)
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Recursive function which will check for equality of the invocation list.
|
|
private bool InvocationListEquals(MulticastDelegate d)
|
|
{
|
|
if (!base.Equals(d))
|
|
return false;
|
|
if (_prev == d._prev)
|
|
return true;
|
|
if (_prev == null)
|
|
return (d._prev == null) ? true : false;
|
|
return _prev.InvocationListEquals(d._prev);
|
|
}
|
|
|
|
// This method will combine this delegate with the passed delegate
|
|
// to form a new delegate.
|
|
//| <include path='docs/doc[@for="MulticastDelegate.CombineImpl"]/*' />
|
|
protected override sealed Delegate CombineImpl(Delegate follow)
|
|
{
|
|
// Verify that the types are the same...
|
|
if (this.GetType() != follow.GetType())
|
|
throw new ArgumentException("Arg_DlgtTypeMis");
|
|
|
|
// We always clone the delegate because this delegate is
|
|
// not changed by combine and remove. We can safely tack
|
|
// the follow delegate onto the end of the copy.
|
|
MulticastDelegate d = (MulticastDelegate) ((MulticastDelegate) follow).MemberwiseClone();
|
|
MulticastDelegate root = d;
|
|
while (d._prev != null) {
|
|
d._prev = (MulticastDelegate) d._prev.MemberwiseClone();
|
|
d = d._prev;
|
|
}
|
|
d._prev = (MulticastDelegate) this;
|
|
return root;
|
|
}
|
|
|
|
// This method currently looks backward on the invocation list
|
|
// for an element that has Delegate based equality with value. (Doesn't
|
|
// look at the invocation list.) If this is found we remove it from
|
|
// this list and return a new delegate. If its not found a copy of the
|
|
// current list is returned.
|
|
//| <include path='docs/doc[@for="MulticastDelegate.RemoveImpl"]/*' />
|
|
protected override sealed Delegate RemoveImpl(Delegate value)
|
|
{
|
|
// There is a special case were we are removing using a delegate as
|
|
// the value we need to check for this case
|
|
//
|
|
if (!(value is MulticastDelegate)) {
|
|
if (base.Equals(value))
|
|
return _prev;
|
|
return this;
|
|
}
|
|
|
|
// Look for the delegate...
|
|
MulticastDelegate v = (MulticastDelegate) value;
|
|
if (InternalEquals(v)) {
|
|
int size = v.DelSize();
|
|
MulticastDelegate p = _prev;
|
|
while (--size != 0)
|
|
p = p._prev;
|
|
return p;
|
|
}
|
|
|
|
MulticastDelegate d = (MulticastDelegate) this.MemberwiseClone();
|
|
MulticastDelegate root = d;
|
|
while (d._prev != null && d._prev.InternalEquals(v) != true) {
|
|
d._prev = (MulticastDelegate) d._prev.MemberwiseClone();
|
|
d = d._prev;
|
|
}
|
|
|
|
if (d._prev != null) {
|
|
int size = v.DelSize();
|
|
MulticastDelegate p = d._prev._prev;
|
|
while (--size != 0)
|
|
p = p._prev;
|
|
d._prev = p;
|
|
}
|
|
return root;
|
|
}
|
|
private int DelSize()
|
|
{
|
|
int i=0;
|
|
MulticastDelegate d = this;
|
|
while (d != null) {
|
|
i++;
|
|
d = d._prev;
|
|
}
|
|
return i;
|
|
}
|
|
|
|
|
|
// Stupid helper function to check equality based upon the super class.
|
|
private bool InternalEquals(Delegate d)
|
|
{
|
|
if (!base.Equals(d))
|
|
return false;
|
|
if (((MulticastDelegate) d)._prev != null) {
|
|
if (_prev == null)
|
|
return false;
|
|
return _prev.InternalEquals(((MulticastDelegate) d)._prev);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
// This method returns the Invocation list of this multicast delegate.
|
|
//| <include path='docs/doc[@for="MulticastDelegate.GetInvocationList"]/*' />
|
|
public override sealed Delegate[] GetInvocationList() {
|
|
int i = 0;
|
|
MulticastDelegate p;
|
|
|
|
// How big is the invocation list?
|
|
for (p = this; p != null; p = p._prev)
|
|
i++;
|
|
|
|
// Create an array of delegate copies and each
|
|
// element into the array (Need to reverse the order and make sure
|
|
// we set the _prev to null.
|
|
Delegate[] del = new Delegate[i];
|
|
for (p = this; p != null; p = p._prev) {
|
|
del[--i] = (Delegate) p.MemberwiseClone();
|
|
((MulticastDelegate) del[i])._prev = null;
|
|
}
|
|
return del;
|
|
}
|
|
|
|
// private static bool operator equals(MulticastDelegate d1, MulticastDelegate d2) {
|
|
// if ((Object)d1 == null)
|
|
// return (Object)d2 == null;
|
|
// return d1.Equals(d2);
|
|
// }
|
|
|
|
//| <include path='docs/doc[@for="MulticastDelegate.operatorEQ"]/*' />
|
|
public static bool operator ==(MulticastDelegate d1, MulticastDelegate d2) {
|
|
if ((Object)d1 == null)
|
|
return (Object)d2 == null;
|
|
return d1.Equals(d2);
|
|
}
|
|
|
|
//| <include path='docs/doc[@for="MulticastDelegate.operatorNE"]/*' />
|
|
public static bool operator !=(MulticastDelegate d1, MulticastDelegate d2) {
|
|
if ((Object)d1 == null)
|
|
return (Object)d2 != null;
|
|
return !d1.Equals(d2);
|
|
}
|
|
|
|
//| <include path='docs/doc[@for="MulticastDelegate.GetHashCode"]/*' />
|
|
public override sealed int GetHashCode() {
|
|
return base.GetHashCode();
|
|
}
|
|
|
|
}
|
|
}
|