// ==++==
//
//
// Copyright (c) 2002 Microsoft Corporation. All rights reserved.
//
// The use and distribution terms for this software are contained in the file
// named license.txt, which can be found in the root of this distribution.
// By using this software in any fashion, you are agreeing to be bound by the
// terms of this license.
//
// You must not remove this notice, or any other, from this software.
//
//
// ==--==
namespace System {
using System;
using System.Reflection;
using System.Threading;
using System.Runtime.Serialization;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
/// <include file='doc\Delegate.uex' path='docs/doc[@for="Delegate"]/*' />
[Serializable()]
public abstract class Delegate : ICloneable, ISerializable
{
// _method is the MethodInfo representing the target, this is set by
// InternalCreate.
private IntPtr _methodPtr;
// _target is the object we will invoke on
private Object _target;
private RuntimeMethodInfo _method = null;
// In the case of a static method passed to a delegate, this field stores
// whatever _methodPtr would have stored: and _methodPtr points to a
// small thunk which removes the "this" pointer before going on
// to _methodPtrAux.
private IntPtr _methodPtrAux = IntPtr.Zero;
// This constructor is called from the class generated by the
// compiler generated code
/// <include file='doc\Delegate.uex' path='docs/doc[@for="Delegate.Delegate"]/*' />
protected Delegate(Object target,String method)
{
if (target == null)
throw new ArgumentNullException("target");
if (method == null)
throw new ArgumentNullException("method");
InternalCreate(target,method,false);
}
// This constructor is called from a class to generate a
// delegate based upon a static method name and the Type object
// for the class defining the method.
/// <include file='doc\Delegate.uex' path='docs/doc[@for="Delegate.Delegate1"]/*' />
protected Delegate(Type target,String method)
{
if (target == null)
throw new ArgumentNullException("target");
if (!(target is RuntimeType))
throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeType"), "target");
if (method == null)
throw new ArgumentNullException("method");
InternalCreateStatic((RuntimeType)target,method);
}
// Protect the default constructor so you can't build a delegate
private Delegate() {}
/// <include file='doc\Delegate.uex' path='docs/doc[@for="Delegate.DynamicInvoke"]/*' />
public Object DynamicInvoke(Object[] args)
{
return DynamicInvokeImpl(args);
}
/// <include file='doc\Delegate.uex' path='docs/doc[@for="Delegate.DynamicInvokeImpl"]/*' />
protected virtual Object DynamicInvokeImpl(Object[] args)
{
if (_method == null)
_method = InternalFindMethodInfo();
// Use internal version of invoke to avoid access check (performed
// during delegate creation).
return _method.InternalInvoke(_target,BindingFlags.Default,null,args,null,false);
}
// equals returns true IIF the delegate is not null and has the
// same target, method and invocation list as this object
/// <include file='doc\Delegate.uex' path='docs/doc[@for="Delegate.Equals"]/*' />
public override bool Equals(Object obj)
{
if (obj != null && obj is Delegate) {
Delegate d = (Delegate) obj;
if (IsStatic()) {
if (_methodPtrAux==d._methodPtrAux) {
return true;
}
} else {
if (d._target == _target && Method.Equals(d.Method)) {
return true;
}
}
}
return false;
}
/// <include file='doc\Delegate.uex' path='docs/doc[@for="Delegate.GetHashCode"]/*' />
public override int GetHashCode()
{
if (IsStatic())
return unchecked((int)((long)this._methodPtrAux));
else
return unchecked((int)((long)this._methodPtr));
}
// Combine creates a new delegate based upon the contents of the
// delegates passed in.
/// <include file='doc\Delegate.uex' path='docs/doc[@for="Delegate.Combine"]/*' />
public static Delegate Combine(Delegate a, Delegate b)
{
// boundry conditions -- if either (or both) delegates is null
// return the other.
if (a == null)
return b;
if (b == null)
return a;
// Verify that the types are the same...
if (a.GetType() != b.GetType())
throw new ArgumentException(Environment.GetResourceString("Arg_DlgtTypeMis"));
return a.CombineImpl(b);
}
// This method creates a new delegate based upon the passed
// array of delegates.
/// <include file='doc\Delegate.uex' path='docs/doc[@for="Delegate.Combine1"]/*' />
public static Delegate Combine(Delegate[] delegates)
{
if (delegates == null || delegates.Length == 0)
return null;
Delegate d = delegates[0];
for (int i = 1; i < delegates.Length; i++)
d = Combine(d,delegates[i]);
return d;
}
// Return an array of delegates that represent the invocation list.
// This is basically THIS for a Delegate. MulticastDelegates may
// have multiple members.
/// <include file='doc\Delegate.uex' path='docs/doc[@for="Delegate.GetInvocationList"]/*' />
public virtual Delegate[] GetInvocationList() {
Delegate[] d = new Delegate[1];
d[0] = this;
return d;
}
// This routine will return the method
/// <include file='doc\Delegate.uex' path='docs/doc[@for="Delegate.Method"]/*' />
public MethodInfo Method
{
get {
if (_method == null)
_method = InternalFindMethodInfo();
return _method;
}
}
/// <include file='doc\Delegate.uex' path='docs/doc[@for="Delegate.GetMethodImpl"]/*' />
protected virtual MethodInfo GetMethodImpl()
{
return Method;
}
// This routine will return the target
/// <include file='doc\Delegate.uex' path='docs/doc[@for="Delegate.Target"]/*' />
public Object Target
{
get {return IsStatic() ? null : _target;}
}
//A quick test to see if this is a delegate to a static method.
private bool IsStatic() {
if (_target is Delegate) {
return true;
}
return false;
}
// This will remove the value delegate from the source delegate
// if it found.
/// <include file='doc\Delegate.uex' path='docs/doc[@for="Delegate.Remove"]/*' />
public static Delegate Remove(Delegate source, Delegate value)
{
if (source == null)
return null;
if (value == null)
return source;
return source.RemoveImpl(value);
}
// This is an internal routine that is called to do the combine. We
// use this to do the combine because the Combine routines are static
// final methods. In Delegate, this simply throws a MulticastNotSupportedException
// error. Multicast delegate must implement this.
/// <include file='doc\Delegate.uex' path='docs/doc[@for="Delegate.CombineImpl"]/*' />
protected virtual Delegate CombineImpl(Delegate d)
{
throw new MulticastNotSupportedException(Environment.GetResourceString("Multicast_Combine"));
}
// This is an internal routine that is called to do the remove. We use this
// to do the remove because Remove is a static final method. Here we simply
// make sure that d is equal to this and return null or this.
/// <include file='doc\Delegate.uex' path='docs/doc[@for="Delegate.RemoveImpl"]/*' />
protected virtual Delegate RemoveImpl(Delegate d)
{
if (_target == d._target && Method.Equals(d.Method))
//if (_target == d._target && _methodPtr == d._methodPtr)
return null;
else
return this;
}
/// <include file='doc\Delegate.uex' path='docs/doc[@for="Delegate.Clone"]/*' />
public virtual Object Clone()
{
return MemberwiseClone();
}
// Create a new delegate given a delegate class, an object and the
// name of a method.
/// <include file='doc\Delegate.uex' path='docs/doc[@for="Delegate.CreateDelegate"]/*' />
public static Delegate CreateDelegate(Type type,Object target,String method) {
if (type == null)
throw new ArgumentNullException("type");
if (!(type is RuntimeType))
throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeType"), "type");
if (target == null)
throw new ArgumentNullException("target");
if (method == null)
throw new ArgumentNullException("method");
Type c = type.BaseType;
if (c == null || (c != typeof(Delegate) && c != typeof(MulticastDelegate)))
throw new ArgumentException(Environment.GetResourceString("Arg_MustBeDelegate"),"type");
Delegate d = InternalAlloc((RuntimeType)type);
d.InternalCreate(target,method,false);
return d;
}
// Create a new delegate given a delegate class, an object and the
// name of a method.
/// <include file='doc\Delegate.uex' path='docs/doc[@for="Delegate.CreateDelegate3"]/*' />
public static Delegate CreateDelegate(Type type,Object target,String method,bool ignoreCase) {
if (type == null)
throw new ArgumentNullException("type");
if (!(type is RuntimeType))
throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeType"), "type");
if (target == null)
throw new ArgumentNullException("target");
if (method == null)
throw new ArgumentNullException("method");
Type c = type.BaseType;
if (c == null || (c != typeof(Delegate) && c != typeof(MulticastDelegate)))
throw new ArgumentException(Environment.GetResourceString("Arg_MustBeDelegate"),"type");
Delegate d = InternalAlloc((RuntimeType)type);
d.InternalCreate(target,method,ignoreCase);
return d;
}
/// <include file='doc\Delegate.uex' path='docs/doc[@for="Delegate.CreateDelegate1"]/*' />
public static Delegate CreateDelegate(Type type, Type target, String method) {
if (type == null)
throw new ArgumentNullException("type");
if (!(type is RuntimeType))
throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeType"), "type");
if (target == null)
throw new ArgumentNullException("target");
if (!(target is RuntimeType))
throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeType"), "target");
if (method == null)
throw new ArgumentNullException("method");
Type c = type.BaseType;
if (c == null || (c != typeof(Delegate) && c != typeof(MulticastDelegate)))
throw new ArgumentException(Environment.GetResourceString("Arg_MustBeDelegate"),"type");
Delegate d = InternalAlloc((RuntimeType)type);
d.InternalCreateStatic((RuntimeType)target,method);
return d;
}
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private extern void NeverCallThis(Object target, IntPtr slot);
/// <include file='doc\Delegate.uex' path='docs/doc[@for="Delegate.CreateDelegate2"]/*' />
public static Delegate CreateDelegate(Type type,MethodInfo method) {
// Validate the parameters.
if (type == null)
throw new ArgumentNullException("type");
if (!(type is RuntimeType))
throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeType"), "type");
if (method == null)
throw new ArgumentNullException("method");
if (!(method is RuntimeMethodInfo))
throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeMethodInfo"), "method");
Type c = type.BaseType;
if (c == null || (c != typeof(Delegate) && c != typeof(MulticastDelegate)))
throw new ArgumentException(Environment.GetResourceString("Arg_MustBeDelegate"),"type");
if (!method.IsStatic)
throw new ArgumentException(Environment.GetResourceString("Arg_MustBeStatic"),"method");
// Find the Invoke method
MethodInfo m = type.GetMethod("Invoke");
if (m == null)
throw new InvalidProgramException("Didn't find Delegate Invoke method.");
if (!(m is RuntimeMethodInfo))
throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeMethodInfo"), "type.Invoke");
// Initialize the method...
Delegate d = InternalAlloc((RuntimeType)type);
d.InternalCreateMethod((RuntimeMethodInfo)m,(RuntimeMethodInfo)method);
return d;
}
// Big cheat to get the internal delegate.
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private extern static Delegate InternalAlloc(RuntimeType type);
// This method is the internal native method that initializes the
// the delegate. It will initialize all of the internal fields
// above.
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal extern void InternalCreate(Object target, String method, bool ignoreCase);
// Internal create for a static method
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal extern void InternalCreateStatic(RuntimeType target, String method);
// Internal create for a static method
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal extern void InternalCreateMethod(RuntimeMethodInfo invokeMeth,RuntimeMethodInfo targetMethod);
// Internal method to get the reflection method info
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal extern RuntimeMethodInfo InternalFindMethodInfo();
// InternalCreateMethod will create a delegate based upon the MethodInfo..
// The method must be static
/// <include file='doc\Delegate.uex' path='docs/doc[@for="Delegate.operatorEQ"]/*' />
public static bool operator ==(Delegate d1, Delegate d2) {
if ((Object)d1 == null)
return (Object)d2 == null;
return d1.Equals(d2);
}
/// <include file='doc\Delegate.uex' path='docs/doc[@for="Delegate.operatorNE"]/*' />
public static bool operator != (Delegate d1, Delegate d2) {
if ((Object)d1 == null)
return (Object)d2 != null;
return !d1.Equals(d2);
}
//
// Implementation of ISerializable
//
/// <include file='doc\Delegate.uex' path='docs/doc[@for="Delegate.GetObjectData"]/*' />
public virtual void GetObjectData(SerializationInfo info, StreamingContext context) {
if (!IsStatic()) {
DelegateSerializationHolder.GetDelegateSerializationInfo(info, this.GetType(), _target, Method, 0);
} else {
DelegateSerializationHolder.GetDelegateSerializationInfo(info, this.GetType(), null, Method, 0);
}
}
//
// This is just designed to prevent compiler warnings.
// This field is used from native, but we need to prevent the compiler warnings.
//
#if _DEBUG
private void DontTouchThis() {
_methodPtr = IntPtr.Zero;
_target = null;
}
#endif
}
}