File: system\reflection\methodbase.cs
Project: ndp\clr\src\bcl\mscorlib.csproj (mscorlib)
// ==++==
// 
//   Copyright(c) Microsoft Corporation.  All rights reserved.
// 
// ==--==
// <OWNER>Microsoft</OWNER>
// 
 
namespace System.Reflection
{
    using System;
    using System.Diagnostics;
    using System.Globalization;
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;
    using System.Security.Permissions;
    using System.Text;
    using System.Threading;
 
    //
    // Invocation cached flags. Those are used in unmanaged code as well
    // so be careful if you change them
    //
    [Flags]
    internal enum INVOCATION_FLAGS : uint
    {
        INVOCATION_FLAGS_UNKNOWN = 0x00000000,
        INVOCATION_FLAGS_INITIALIZED = 0x00000001,
        // it's used for both method and field to signify that no access is allowed
        INVOCATION_FLAGS_NO_INVOKE = 0x00000002,
        INVOCATION_FLAGS_NEED_SECURITY = 0x00000004,
        // Set for static ctors and ctors on abstract types, which
        // can be invoked only if the "this" object is provided (even if it's null).
        INVOCATION_FLAGS_NO_CTOR_INVOKE = 0x00000008,
        // because field and method are different we can reuse the same bits
        // method
        INVOCATION_FLAGS_IS_CTOR = 0x00000010,
        INVOCATION_FLAGS_RISKY_METHOD = 0x00000020,
        INVOCATION_FLAGS_NON_W8P_FX_API = 0x00000040,
        INVOCATION_FLAGS_IS_DELEGATE_CTOR = 0x00000080,
        INVOCATION_FLAGS_CONTAINS_STACK_POINTERS = 0x00000100,
        // field
        INVOCATION_FLAGS_SPECIAL_FIELD = 0x00000010,
        INVOCATION_FLAGS_FIELD_SPECIAL_CAST = 0x00000020,
 
        // temporary flag used for flagging invocation of method vs ctor
        // this flag never appears on the instance m_invocationFlag and is simply
        // passed down from within ConstructorInfo.Invoke()
        INVOCATION_FLAGS_CONSTRUCTOR_INVOKE = 0x10000000,
    }
 
    [Serializable]
    [ClassInterface(ClassInterfaceType.None)]
    [ComDefaultInterface(typeof(_MethodBase))]
#pragma warning disable 618
    [PermissionSetAttribute(SecurityAction.InheritanceDemand, Name = "FullTrust")]
#pragma warning restore 618
    [System.Runtime.InteropServices.ComVisible(true)]
    public abstract class MethodBase : MemberInfo, _MethodBase
    {
        #region Static Members
        public static MethodBase GetMethodFromHandle(RuntimeMethodHandle handle)
        {
            if (handle.IsNullHandle())
                throw new ArgumentException(Environment.GetResourceString("Argument_InvalidHandle"));
 
            MethodBase m = RuntimeType.GetMethodBase(handle.GetMethodInfo());
 
            Type declaringType = m.DeclaringType;
            if (declaringType != null && declaringType.IsGenericType)
                throw new ArgumentException(String.Format(
                    CultureInfo.CurrentCulture, Environment.GetResourceString("Argument_MethodDeclaringTypeGeneric"), 
                    m, declaringType.GetGenericTypeDefinition()));
 
            return m;
        }
 
        [System.Runtime.InteropServices.ComVisible(false)]
        public static MethodBase GetMethodFromHandle(RuntimeMethodHandle handle, RuntimeTypeHandle declaringType)
        {
            if (handle.IsNullHandle())
                throw new ArgumentException(Environment.GetResourceString("Argument_InvalidHandle"));
 
            return RuntimeType.GetMethodBase(declaringType.GetRuntimeType(), handle.GetMethodInfo());
        }
 
        [System.Security.DynamicSecurityMethod] // Specify DynamicSecurityMethod attribute to prevent inlining of the caller.
        [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
        public static MethodBase GetCurrentMethod()
        {
            StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
            return RuntimeMethodInfo.InternalGetCurrentMethod(ref stackMark);
        }
        #endregion
 
        #region Constructor
        protected MethodBase() { }
        #endregion
 
#if !FEATURE_CORECLR
        public static bool operator ==(MethodBase left, MethodBase right)
        {
            if (ReferenceEquals(left, right))
                return true;
 
            if ((object)left == null || (object)right == null)
                return false;
 
            MethodInfo method1, method2;
            ConstructorInfo constructor1, constructor2;
 
            if ((method1 = left as MethodInfo) != null && (method2 = right as MethodInfo) != null)
                return method1 == method2;
            else if ((constructor1 = left as ConstructorInfo) != null && (constructor2 = right as ConstructorInfo) != null)
                return constructor1 == constructor2;
 
            return false;
        }
 
        public static bool operator !=(MethodBase left, MethodBase right)
        {
            return !(left == right);
        }
#endif // !FEATURE_CORECLR
 
        public override bool Equals(object obj)
        {
            return base.Equals(obj);
        }
 
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }
 
        #region Internal Members
        // used by EE
        [System.Security.SecurityCritical]
        private IntPtr GetMethodDesc() { return MethodHandle.Value; }
 
#if FEATURE_APPX
 
        // The C# dynamic and VB late bound binders need to call this API. Since we don't have time to make this
        // public in Dev11, the C# and VB binders currently call this through a delegate. 
        // When we make this API public (hopefully) in Dev12 we need to change the C# and VB binders to call this
        // probably statically. The code is located in:
        // C#: ndp\fx\src\CSharp\Microsoft\CSharp\SymbolTable.cs - Microsoft.CSharp.RuntimeBinder.SymbolTable..cctor
        // VB: vb\runtime\msvbalib\helpers\Symbols.vb - Microsoft.VisualBasic.CompilerServices.Symbols..cctor
        internal virtual bool IsDynamicallyInvokable
        {
            get
            {
                return true;
            }
        }
#endif
        #endregion
 
        #region Public Abstract\Virtual Members
        internal virtual ParameterInfo[] GetParametersNoCopy() { return GetParameters (); }
 
        [System.Diagnostics.Contracts.Pure]
        public abstract ParameterInfo[] GetParameters();
 
        public virtual MethodImplAttributes MethodImplementationFlags
        {
            get
            {
                return GetMethodImplementationFlags();
            }
        }
 
        public abstract MethodImplAttributes GetMethodImplementationFlags();
 
        public abstract RuntimeMethodHandle MethodHandle { get; }   
 
        public abstract MethodAttributes Attributes  { get; }    
 
        public abstract Object Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture);
 
        public virtual CallingConventions CallingConvention { get { return CallingConventions.Standard; } }
 
        [System.Runtime.InteropServices.ComVisible(true)]
        public virtual Type[] GetGenericArguments() { throw new NotSupportedException(Environment.GetResourceString("NotSupported_SubclassOverride")); }
        
        public virtual bool IsGenericMethodDefinition { get { return false; } }
 
        public virtual bool ContainsGenericParameters { get { return false; } }
 
        public virtual bool IsGenericMethod { get { return false; } }
 
        public virtual bool IsSecurityCritical { get { throw new NotImplementedException(); } }
 
        public virtual bool IsSecuritySafeCritical { get { throw new NotImplementedException(); } }
 
        public virtual bool IsSecurityTransparent { get { throw new NotImplementedException(); } }
 
        #endregion
 
        #region Public Members
        [DebuggerStepThroughAttribute]
        [Diagnostics.DebuggerHidden]
        public Object Invoke(Object obj, Object[] parameters)
        {
            // Theoretically we should set up a LookForMyCaller stack mark here and pass that along.
            // But to maintain backward compatibility we can't switch to calling an 
            // internal overload that takes a stack mark.
            // Fortunately the stack walker skips all the reflection invocation frames including this one.
            // So this method will never be returned by the stack walker as the caller.
            // See SystemDomain::CallersMethodCallbackWithStackMark in AppDomain.cpp.
            return Invoke(obj, BindingFlags.Default, null, parameters, null);
        }
 
        public bool IsPublic  { get { return(Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Public; } }
 
        public bool IsPrivate { get { return(Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Private; } }
 
        public bool IsFamily { get { return(Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Family; } }
 
        public bool IsAssembly { get { return(Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Assembly; } }
 
        public bool IsFamilyAndAssembly { get { return(Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.FamANDAssem; } }
 
        public bool IsFamilyOrAssembly { get {return(Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.FamORAssem; } }
 
        public bool IsStatic { get { return(Attributes & MethodAttributes.Static) != 0; } }
 
        public bool IsFinal { get { return(Attributes & MethodAttributes.Final) != 0; }
        }
        public bool IsVirtual { get { return(Attributes & MethodAttributes.Virtual) != 0; }
        }   
        public bool IsHideBySig { get { return(Attributes & MethodAttributes.HideBySig) != 0; } }  
 
        public bool IsAbstract { get { return(Attributes & MethodAttributes.Abstract) != 0; } }
 
        public bool IsSpecialName { get { return(Attributes & MethodAttributes.SpecialName) != 0; } }
 
        [System.Runtime.InteropServices.ComVisible(true)]
        public bool IsConstructor 
        {
            get 
            {
                // To be backward compatible we only return true for instance RTSpecialName ctors.
                return (this is ConstructorInfo &&
                        !IsStatic &&
                        ((Attributes & MethodAttributes.RTSpecialName) == MethodAttributes.RTSpecialName));
            }
        }
 
        [System.Security.SecuritySafeCritical]
#pragma warning disable 618
        [ReflectionPermissionAttribute(SecurityAction.Demand, Flags=ReflectionPermissionFlag.MemberAccess)]            
#pragma warning restore 618
        public virtual MethodBody GetMethodBody()
        {
            throw new InvalidOperationException();
        }        
        #endregion
        
        #region Internal Methods
        // helper method to construct the string representation of the parameter list
        // 
 
        internal static string ConstructParameters(Type[] parameterTypes, CallingConventions callingConvention, bool serialization)
        {
            StringBuilder sbParamList = new StringBuilder();
            string comma = "";
 
            for (int i = 0; i < parameterTypes.Length; i++)
            {
                Type t = parameterTypes[i];
 
                sbParamList.Append(comma);
 
                string typeName = t.FormatTypeName(serialization);
 
                // Legacy: Why use "ByRef" for by ref parameters? What language is this? 
                // VB uses "ByRef" but it should precede (not follow) the parameter name.
                // Why don't we just use "&"?
                if (t.IsByRef && !serialization)
                {
                    sbParamList.Append(typeName.TrimEnd(new char[] { '&' }));
                    sbParamList.Append(" ByRef");
                }
                else
                {
                    sbParamList.Append(typeName);
                }
 
                comma = ", ";
            }
 
            if ((callingConvention & CallingConventions.VarArgs) == CallingConventions.VarArgs)
            {
                sbParamList.Append(comma);
                sbParamList.Append("...");
            }
 
            return sbParamList.ToString();
        }
 
        internal string FullName
        {
            get
            {
                return String.Format("{0}.{1}", DeclaringType.FullName, FormatNameAndSig());
            }
        }
        internal string FormatNameAndSig()
        {
            return FormatNameAndSig(false);
        }
 
        internal virtual string FormatNameAndSig(bool serialization)
        {
            // Serialization uses ToString to resolve MethodInfo overloads.
            StringBuilder sbName = new StringBuilder(Name);
 
            sbName.Append("(");
            sbName.Append(ConstructParameters(GetParameterTypes(), CallingConvention, serialization));
            sbName.Append(")");
 
            return sbName.ToString();
        }
 
        internal virtual Type[] GetParameterTypes()
        {
            ParameterInfo[] paramInfo = GetParametersNoCopy();
 
            Type[] parameterTypes = new Type[paramInfo.Length];
            for (int i = 0; i < paramInfo.Length; i++)
                parameterTypes[i] = paramInfo[i].ParameterType;
 
            return parameterTypes;
        }
 
        [System.Security.SecuritySafeCritical]
        internal Object[] CheckArguments(Object[] parameters, Binder binder, 
            BindingFlags invokeAttr, CultureInfo culture, Signature sig)
        {
            // copy the arguments in a different array so we detach from any user changes 
            Object[] copyOfParameters = new Object[parameters.Length];
            
            ParameterInfo[] p = null;
            for (int i = 0; i < parameters.Length; i++)
            {
                Object arg = parameters[i];
                RuntimeType argRT = sig.Arguments[i];
                
                if (arg == Type.Missing)
                {
                    if (p == null) 
                        p = GetParametersNoCopy();
                    if (p[i].DefaultValue == System.DBNull.Value)
                        throw new ArgumentException(Environment.GetResourceString("Arg_VarMissNull"),"parameters");
                    arg = p[i].DefaultValue;
                }
                copyOfParameters[i] = argRT.CheckValue(arg, binder, culture, invokeAttr);
            }
 
            return copyOfParameters;
        }
        #endregion
 
        #region _MethodBase Implementation
#if !FEATURE_CORECLR
        Type _MethodBase.GetType() { return base.GetType(); }
        bool _MethodBase.IsPublic { get { return IsPublic; } }
        bool _MethodBase.IsPrivate { get { return IsPrivate; } }
        bool _MethodBase.IsFamily { get { return IsFamily; } }
        bool _MethodBase.IsAssembly { get { return IsAssembly; } }
        bool _MethodBase.IsFamilyAndAssembly { get { return IsFamilyAndAssembly; } }
        bool _MethodBase.IsFamilyOrAssembly { get { return IsFamilyOrAssembly; } }
        bool _MethodBase.IsStatic { get { return IsStatic; } }
        bool _MethodBase.IsFinal { get { return IsFinal; } }
        bool _MethodBase.IsVirtual { get { return IsVirtual; } }
        bool _MethodBase.IsHideBySig { get { return IsHideBySig; } }
        bool _MethodBase.IsAbstract { get { return IsAbstract; } }
        bool _MethodBase.IsSpecialName { get { return IsSpecialName; } }
        bool _MethodBase.IsConstructor { get { return IsConstructor; } }
 
        void _MethodBase.GetTypeInfoCount(out uint pcTInfo)
        {
            throw new NotImplementedException();
        }
 
        void _MethodBase.GetTypeInfo(uint iTInfo, uint lcid, IntPtr ppTInfo)
        {
            throw new NotImplementedException();
        }
 
        void _MethodBase.GetIDsOfNames([In] ref Guid riid, IntPtr rgszNames, uint cNames, uint lcid, IntPtr rgDispId)
        {
            throw new NotImplementedException();
        }
 
        // If you implement this method, make sure to include _MethodBase.Invoke in VM\DangerousAPIs.h and 
        // include _MethodBase in SystemDomain::IsReflectionInvocationMethod in AppDomain.cpp.
        void _MethodBase.Invoke(uint dispIdMember, [In] ref Guid riid, uint lcid, short wFlags, IntPtr pDispParams, IntPtr pVarResult, IntPtr pExcepInfo, IntPtr puArgErr)
        {
            throw new NotImplementedException();
        }
#endif
        #endregion
    }
 
}