// ==++== // // // 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; /// [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 /// 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. /// 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() {} /// public Object DynamicInvoke(Object[] args) { return DynamicInvokeImpl(args); } /// 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 /// 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; } /// 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. /// 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. /// 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. /// public virtual Delegate[] GetInvocationList() { Delegate[] d = new Delegate[1]; d[0] = this; return d; } // This routine will return the method /// public MethodInfo Method { get { if (_method == null) _method = InternalFindMethodInfo(); return _method; } } /// protected virtual MethodInfo GetMethodImpl() { return Method; } // This routine will return the 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. /// 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. /// 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. /// 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; } /// public virtual Object Clone() { return MemberwiseClone(); } // Create a new delegate given a delegate class, an object and the // name of a method. /// 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. /// 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; } /// 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); /// 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 /// public static bool operator ==(Delegate d1, Delegate d2) { if ((Object)d1 == null) return (Object)d2 == null; return d1.Equals(d2); } /// public static bool operator != (Delegate d1, Delegate d2) { if ((Object)d1 == null) return (Object)d2 != null; return !d1.Equals(d2); } // // Implementation of ISerializable // /// 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 } }