3 // Copyright(c) Microsoft Corporation. All rights reserved.
6 // <OWNER>[....]</OWNER>
9 namespace System.Reflection
12 using System.Collections.Generic;
13 using System.Diagnostics.Contracts;
14 using System.Runtime.InteropServices;
15 using System.Runtime.Serialization;
16 using System.Runtime.CompilerServices;
18 using System.Runtime.Remoting.Metadata;
19 #endif //FEATURE_REMOTING
20 using System.Security.Permissions;
21 using System.Threading;
22 using MdToken = System.Reflection.MetadataToken;
25 [ClassInterface(ClassInterfaceType.None)]
26 [ComDefaultInterface(typeof(_ParameterInfo))]
27 [System.Runtime.InteropServices.ComVisible(true)]
28 public class ParameterInfo : _ParameterInfo, ICustomAttributeProvider, IObjectReference
30 #region Legacy Protected Members
31 protected String NameImpl;
32 protected Type ClassImpl;
33 protected int PositionImpl;
34 protected ParameterAttributes AttrsImpl;
35 protected Object DefaultValueImpl; // cannot cache this as it may be non agile user defined enum
36 protected MemberInfo MemberImpl;
39 #region Legacy Private Members
40 // These are here only for backwards compatibility -- they are not set
41 // until this instance is serialized, so don't rely on their values from
43 #pragma warning disable 169
45 private IntPtr _importer;
49 private bool bExtraConstChecked;
50 #pragma warning restore 169
54 protected ParameterInfo()
59 #region Internal Members
60 // this is an internal api for DynamicMethod. A better solution is to change the relationship
61 // between ParameterInfo and ParameterBuilder so that a ParameterBuilder can be seen as a writer
62 // api over a ParameterInfo. However that is a possible breaking change so it needs to go through some process first
63 internal void SetName(String name)
68 internal void SetAttributes(ParameterAttributes attributes)
70 AttrsImpl = attributes;
74 #region Public Methods
75 public virtual Type ParameterType
83 public virtual String Name
91 public virtual bool HasDefaultValue { get { throw new NotImplementedException(); } }
93 public virtual Object DefaultValue { get { throw new NotImplementedException(); } }
94 public virtual Object RawDefaultValue { get { throw new NotImplementedException(); } }
96 public virtual int Position { get { return PositionImpl; } }
97 public virtual ParameterAttributes Attributes { get { return AttrsImpl; } }
99 public virtual MemberInfo Member {
101 Contract.Ensures(Contract.Result<MemberInfo>() != null);
106 public bool IsIn { get { return((Attributes & ParameterAttributes.In) != 0); } }
107 public bool IsOut { get { return((Attributes & ParameterAttributes.Out) != 0); } }
109 public bool IsLcid { get { return((Attributes & ParameterAttributes.Lcid) != 0); } }
111 public bool IsRetval { get { return((Attributes & ParameterAttributes.Retval) != 0); } }
112 public bool IsOptional { get { return((Attributes & ParameterAttributes.Optional) != 0); } }
114 public virtual int MetadataToken
118 // This API was made virtual in V4. Code compiled against V2 might use
119 // "call" rather than "callvirt" to call it.
120 // This makes sure those code still works.
121 RuntimeParameterInfo rtParam = this as RuntimeParameterInfo;
123 return rtParam.MetadataToken;
125 // return a null token
126 return (int)MetadataTokenType.ParamDef;
130 public virtual Type[] GetRequiredCustomModifiers()
132 return EmptyArray<Type>.Value;
135 public virtual Type[] GetOptionalCustomModifiers()
137 return EmptyArray<Type>.Value;
141 #region Object Overrides
142 public override String ToString()
144 return ParameterType.FormatTypeName() + " " + Name;
148 public virtual IEnumerable<CustomAttributeData> CustomAttributes
152 return GetCustomAttributesData();
155 #region ICustomAttributeProvider
156 public virtual Object[] GetCustomAttributes(bool inherit)
158 return EmptyArray<Object>.Value;
161 public virtual Object[] GetCustomAttributes(Type attributeType, bool inherit)
163 if (attributeType == null)
164 throw new ArgumentNullException("attributeType");
165 Contract.EndContractBlock();
167 return EmptyArray<Object>.Value;
170 public virtual bool IsDefined(Type attributeType, bool inherit)
172 if (attributeType == null)
173 throw new ArgumentNullException("attributeType");
174 Contract.EndContractBlock();
179 public virtual IList<CustomAttributeData> GetCustomAttributesData()
181 throw new NotImplementedException();
185 #region _ParameterInfo implementation
188 void _ParameterInfo.GetTypeInfoCount(out uint pcTInfo)
190 throw new NotImplementedException();
193 void _ParameterInfo.GetTypeInfo(uint iTInfo, uint lcid, IntPtr ppTInfo)
195 throw new NotImplementedException();
198 void _ParameterInfo.GetIDsOfNames([In] ref Guid riid, IntPtr rgszNames, uint cNames, uint lcid, IntPtr rgDispId)
200 throw new NotImplementedException();
203 void _ParameterInfo.Invoke(uint dispIdMember, [In] ref Guid riid, uint lcid, short wFlags, IntPtr pDispParams, IntPtr pVarResult, IntPtr pExcepInfo, IntPtr puArgErr)
205 throw new NotImplementedException();
211 #region IObjectReference
212 // In V4 RuntimeParameterInfo is introduced.
213 // To support deserializing ParameterInfo instances serialized in earlier versions
214 // we need to implement IObjectReference.
215 [System.Security.SecurityCritical]
216 public object GetRealObject(StreamingContext context)
218 Contract.Ensures(Contract.Result<Object>() != null);
220 // Once all the serializable fields have come in we can set up the real
221 // instance based on just two of them (MemberImpl and PositionImpl).
223 if (MemberImpl == null)
224 throw new SerializationException(Environment.GetResourceString(ResId.Serialization_InsufficientState));
226 ParameterInfo[] args = null;
228 switch (MemberImpl.MemberType)
230 case MemberTypes.Constructor:
231 case MemberTypes.Method:
232 if (PositionImpl == -1)
234 if (MemberImpl.MemberType == MemberTypes.Method)
235 return ((MethodInfo)MemberImpl).ReturnParameter;
237 throw new SerializationException(Environment.GetResourceString(ResId.Serialization_BadParameterInfo));
241 args = ((MethodBase)MemberImpl).GetParametersNoCopy();
243 if (args != null && PositionImpl < args.Length)
244 return args[PositionImpl];
246 throw new SerializationException(Environment.GetResourceString(ResId.Serialization_BadParameterInfo));
249 case MemberTypes.Property:
250 args = ((RuntimePropertyInfo)MemberImpl).GetIndexParametersNoCopy();
252 if (args != null && PositionImpl > -1 && PositionImpl < args.Length)
253 return args[PositionImpl];
255 throw new SerializationException(Environment.GetResourceString(ResId.Serialization_BadParameterInfo));
258 throw new SerializationException(Environment.GetResourceString(ResId.Serialization_NoParameterInfo));
265 internal unsafe sealed class RuntimeParameterInfo : ParameterInfo, ISerializable
267 #region Static Members
268 [System.Security.SecurityCritical] // auto-generated
269 internal unsafe static ParameterInfo[] GetParameters(IRuntimeMethodInfo method, MemberInfo member, Signature sig)
271 Contract.Assert(method is RuntimeMethodInfo || method is RuntimeConstructorInfo);
274 return GetParameters(method, member, sig, out dummy, false);
277 [System.Security.SecurityCritical] // auto-generated
278 internal unsafe static ParameterInfo GetReturnParameter(IRuntimeMethodInfo method, MemberInfo member, Signature sig)
280 Contract.Assert(method is RuntimeMethodInfo || method is RuntimeConstructorInfo);
282 ParameterInfo returnParameter;
283 GetParameters(method, member, sig, out returnParameter, true);
284 return returnParameter;
287 [System.Security.SecurityCritical] // auto-generated
288 internal unsafe static ParameterInfo[] GetParameters(
289 IRuntimeMethodInfo methodHandle, MemberInfo member, Signature sig, out ParameterInfo returnParameter, bool fetchReturnParameter)
291 returnParameter = null;
292 int sigArgCount = sig.Arguments.Length;
293 ParameterInfo[] args = fetchReturnParameter ? null : new ParameterInfo[sigArgCount];
295 int tkMethodDef = RuntimeMethodHandle.GetMethodDef(methodHandle);
298 // Not all methods have tokens. Arrays, pointers and byRef types do not have tokens as they
299 // are generated on the fly by the runtime.
300 if (!MdToken.IsNullToken(tkMethodDef))
302 MetadataImport scope = RuntimeTypeHandle.GetMetadataImport(RuntimeMethodHandle.GetDeclaringType(methodHandle));
304 MetadataEnumResult tkParamDefs;
305 scope.EnumParams(tkMethodDef, out tkParamDefs);
307 cParamDefs = tkParamDefs.Length;
309 // Not all parameters have tokens. Parameters may have no token
310 // if they have no name and no attributes.
311 if (cParamDefs > sigArgCount + 1 /* return type */)
312 throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_ParameterSignatureMismatch"));
314 for (int i = 0; i < cParamDefs; i++)
316 #region Populate ParameterInfos
317 ParameterAttributes attr;
318 int position, tkParamDef = tkParamDefs[i];
320 scope.GetParamDefProps(tkParamDef, out position, out attr);
324 if (fetchReturnParameter == true && position == -1)
326 // more than one return parameter?
327 if (returnParameter != null)
328 throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_ParameterSignatureMismatch"));
330 returnParameter = new RuntimeParameterInfo(sig, scope, tkParamDef, position, attr, member);
332 else if (fetchReturnParameter == false && position >= 0)
334 // position beyong sigArgCount?
335 if (position >= sigArgCount)
336 throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_ParameterSignatureMismatch"));
338 args[position] = new RuntimeParameterInfo(sig, scope, tkParamDef, position, attr, member);
344 // Fill in empty ParameterInfos for those without tokens
345 if (fetchReturnParameter)
347 if (returnParameter == null)
349 returnParameter = new RuntimeParameterInfo(sig, MetadataImport.EmptyImport, 0, -1, (ParameterAttributes)0, member);
354 if (cParamDefs < args.Length + 1)
356 for (int i = 0; i < args.Length; i++)
361 args[i] = new RuntimeParameterInfo(sig, MetadataImport.EmptyImport, 0, i, (ParameterAttributes)0, member);
370 #region Private Statics
371 private static readonly Type s_DecimalConstantAttributeType = typeof(DecimalConstantAttribute);
372 private static readonly Type s_CustomConstantAttributeType = typeof(CustomConstantAttribute);
375 #region Private Data Members
376 // These are new in Whidbey, so we cannot serialize them directly or we break backwards compatibility.
378 private int m_tkParamDef;
380 private MetadataImport m_scope;
382 private Signature m_signature;
384 private volatile bool m_nameIsCached = false;
386 private readonly bool m_noMetadata = false;
388 private bool m_noDefaultValue = false;
390 private MethodBase m_originalMember = null;
393 #region Internal Properties
394 internal MethodBase DefiningMethod
398 MethodBase result = m_originalMember != null ? m_originalMember : MemberImpl as MethodBase;
399 Contract.Assert(result != null);
405 #region VTS magic to serialize/deserialized to/from pre-Whidbey endpoints.
406 [System.Security.SecurityCritical]
407 public void GetObjectData(SerializationInfo info, StreamingContext context)
410 throw new ArgumentNullException("info");
411 Contract.EndContractBlock();
413 // We could be serializing for consumption by a pre-Whidbey
414 // endpoint. Therefore we set up all the serialized fields to look
415 // just like a v1.0/v1.1 instance.
417 // Need to set the type to ParameterInfo so that pre-Whidbey and Whidbey code
418 // can deserialize this. This is also why we cannot simply use [OnSerializing].
419 info.SetType(typeof(ParameterInfo));
421 // Use the properties intead of the fields in case the fields haven't been et
422 // _importer, bExtraConstChecked, and m_cachedData don't need to be set
424 // Now set the legacy fields that the current implementation doesn't
425 // use any more. Note that _importer is a raw pointer that should
426 // never have been serialized in V1. We set it to zero here; if the
427 // deserializer uses it (by calling GetCustomAttributes() on this
428 // instance) they'll AV, but at least it will be a well defined
429 // exception and not a random AV.
431 info.AddValue("AttrsImpl", Attributes);
432 info.AddValue("ClassImpl", ParameterType);
433 info.AddValue("DefaultValueImpl", DefaultValue);
434 info.AddValue("MemberImpl", Member);
435 info.AddValue("NameImpl", Name);
436 info.AddValue("PositionImpl", Position);
437 info.AddValue("_token", m_tkParamDef);
442 // used by RuntimePropertyInfo
443 internal RuntimeParameterInfo(RuntimeParameterInfo accessor, RuntimePropertyInfo property)
444 : this(accessor, (MemberInfo)property)
446 m_signature = property.Signature;
449 private RuntimeParameterInfo(RuntimeParameterInfo accessor, MemberInfo member)
454 // The original owner should always be a method, because this method is only used to
455 // change the owner from a method to a property.
456 m_originalMember = accessor.MemberImpl as MethodBase;
457 Contract.Assert(m_originalMember != null);
459 // Populate all the caches -- we inherit this behavior from RTM
460 NameImpl = accessor.Name;
461 m_nameIsCached = true;
462 ClassImpl = accessor.ParameterType;
463 PositionImpl = accessor.Position;
464 AttrsImpl = accessor.Attributes;
466 // Strictly speeking, property's don't contain paramter tokens
467 // However we need this to make ca's work... oh well...
468 m_tkParamDef = MdToken.IsNullToken(accessor.MetadataToken) ? (int)MetadataTokenType.ParamDef : accessor.MetadataToken;
469 m_scope = accessor.m_scope;
472 private RuntimeParameterInfo(
473 Signature signature, MetadataImport scope, int tkParamDef,
474 int position, ParameterAttributes attributes, MemberInfo member)
476 Contract.Requires(member != null);
477 Contract.Assert(MdToken.IsNullToken(tkParamDef) == scope.Equals(MetadataImport.EmptyImport));
478 Contract.Assert(MdToken.IsNullToken(tkParamDef) || MdToken.IsTokenOfType(tkParamDef, MetadataTokenType.ParamDef));
480 PositionImpl = position;
482 m_signature = signature;
483 m_tkParamDef = MdToken.IsNullToken(tkParamDef) ? (int)MetadataTokenType.ParamDef : tkParamDef;
485 AttrsImpl = attributes;
491 // ctor for no metadata MethodInfo in the DynamicMethod and RuntimeMethodInfo cases
492 internal RuntimeParameterInfo(MethodInfo owner, String name, Type parameterType, int position)
496 m_nameIsCached = true;
498 ClassImpl = parameterType;
499 PositionImpl = position;
500 AttrsImpl = ParameterAttributes.None;
501 m_tkParamDef = (int)MetadataTokenType.ParamDef;
502 m_scope = MetadataImport.EmptyImport;
506 #region Public Methods
507 public override Type ParameterType
511 // only instance of ParameterInfo has ClassImpl, all its subclasses don't
512 if (ClassImpl == null)
514 RuntimeType parameterType;
515 if (PositionImpl == -1)
516 parameterType = m_signature.ReturnType;
518 parameterType = m_signature.Arguments[PositionImpl];
520 Contract.Assert(parameterType != null);
521 // different thread could only write ClassImpl to the same value, so ---- is not a problem here
522 ClassImpl = parameterType;
529 public override String Name
531 [System.Security.SecuritySafeCritical] // auto-generated
536 if (!MdToken.IsNullToken(m_tkParamDef))
539 name = m_scope.GetName(m_tkParamDef).ToString();
543 // other threads could only write it to true, so ---- is OK
544 // this field is volatile, so the write ordering is guaranteed
545 m_nameIsCached = true;
553 public override bool HasDefaultValue
557 if (m_noMetadata || m_noDefaultValue)
560 object defaultValue = GetDefaultValueInternal(false);
562 return (defaultValue != DBNull.Value);
566 public override Object DefaultValue { get { return GetDefaultValue(false); } }
567 public override Object RawDefaultValue { get { return GetDefaultValue(true); } }
569 private Object GetDefaultValue(bool raw)
571 // OLD COMMENT (Is this even true?)
572 // Cannot cache because default value could be non-agile user defined enumeration.
577 // for dynamic method we pretend to have cached the value so we do not go to metadata
578 object defaultValue = GetDefaultValueInternal(raw);
580 if (defaultValue == DBNull.Value)
582 #region Handle case if no default value was found
583 #if FEATURE_LEGACYNETCF
584 if (CompatibilitySwitches.IsAppEarlierThanWindowsPhone8)
590 // If the argument is marked as optional then the default value is Missing.Value.
591 defaultValue = Type.Missing;
599 // returns DBNull.Value if the parameter doesn't have a default value
600 [System.Security.SecuritySafeCritical]
601 private Object GetDefaultValueInternal(bool raw)
603 Contract.Assert(!m_noMetadata);
605 if (m_noDefaultValue)
608 object defaultValue = null;
610 // Why check the parameter type only for DateTime and only for the ctor arguments?
611 // No check on the parameter type is done for named args and for Decimal.
613 // We should move this after MdToken.IsNullToken(m_tkParamDef) and combine it
614 // with the other custom attribute logic. But will that be a breaking change?
615 // For a DateTime parameter on which both an md constant and a ca constant are set,
616 // which one should win?
617 if (ParameterType == typeof(DateTime))
621 CustomAttributeTypedArgument value =
622 CustomAttributeData.Filter(
623 CustomAttributeData.GetCustomAttributes(this), typeof(DateTimeConstantAttribute), 0);
625 if (value.ArgumentType != null)
626 return new DateTime((long)value.Value);
630 object[] dt = GetCustomAttributes(typeof(DateTimeConstantAttribute), false);
631 if (dt != null && dt.Length != 0)
632 return ((DateTimeConstantAttribute)dt[0]).Value;
636 #region Look for a default value in metadata
637 if (!MdToken.IsNullToken(m_tkParamDef))
639 // This will return DBNull.Value if no constant value is defined on m_tkParamDef in the metadata.
640 defaultValue = MdConstant.GetValue(m_scope, m_tkParamDef, ParameterType.GetTypeHandleInternal(), raw);
644 if (defaultValue == DBNull.Value)
646 #region Look for a default value in the custom attributes
649 foreach (CustomAttributeData attr in CustomAttributeData.GetCustomAttributes(this))
651 Type attrType = attr.Constructor.DeclaringType;
653 if (attrType == typeof(DateTimeConstantAttribute))
655 defaultValue = DateTimeConstantAttribute.GetRawDateTimeConstant(attr);
657 else if (attrType == typeof(DecimalConstantAttribute))
659 defaultValue = DecimalConstantAttribute.GetRawDecimalConstant(attr);
661 else if (attrType.IsSubclassOf(s_CustomConstantAttributeType))
663 defaultValue = CustomConstantAttribute.GetRawConstant(attr);
669 Object[] CustomAttrs = GetCustomAttributes(s_CustomConstantAttributeType, false);
670 if (CustomAttrs.Length != 0)
672 defaultValue = ((CustomConstantAttribute)CustomAttrs[0]).Value;
676 CustomAttrs = GetCustomAttributes(s_DecimalConstantAttributeType, false);
677 if (CustomAttrs.Length != 0)
679 defaultValue = ((DecimalConstantAttribute)CustomAttrs[0]).Value;
686 if (defaultValue == DBNull.Value)
687 m_noDefaultValue = true;
692 internal RuntimeModule GetRuntimeModule()
694 RuntimeMethodInfo method = Member as RuntimeMethodInfo;
695 RuntimeConstructorInfo constructor = Member as RuntimeConstructorInfo;
696 RuntimePropertyInfo property = Member as RuntimePropertyInfo;
699 return method.GetRuntimeModule();
700 else if (constructor != null)
701 return constructor.GetRuntimeModule();
702 else if (property != null)
703 return property.GetRuntimeModule();
708 public override int MetadataToken
716 public override Type[] GetRequiredCustomModifiers()
718 return m_signature.GetCustomModifiers(PositionImpl + 1, true);
721 public override Type[] GetOptionalCustomModifiers()
723 return m_signature.GetCustomModifiers(PositionImpl + 1, false);
728 #region ICustomAttributeProvider
729 public override Object[] GetCustomAttributes(bool inherit)
731 if (MdToken.IsNullToken(m_tkParamDef))
732 return EmptyArray<Object>.Value;
734 return CustomAttribute.GetCustomAttributes(this, typeof(object) as RuntimeType);
737 public override Object[] GetCustomAttributes(Type attributeType, bool inherit)
739 if (attributeType == null)
740 throw new ArgumentNullException("attributeType");
741 Contract.EndContractBlock();
743 if (MdToken.IsNullToken(m_tkParamDef))
744 return EmptyArray<Object>.Value;
746 RuntimeType attributeRuntimeType = attributeType.UnderlyingSystemType as RuntimeType;
748 if (attributeRuntimeType == null)
749 throw new ArgumentException(Environment.GetResourceString("Arg_MustBeType"), "attributeType");
751 return CustomAttribute.GetCustomAttributes(this, attributeRuntimeType);
754 [System.Security.SecuritySafeCritical] // auto-generated
755 public override bool IsDefined(Type attributeType, bool inherit)
757 if (attributeType == null)
758 throw new ArgumentNullException("attributeType");
759 Contract.EndContractBlock();
761 if (MdToken.IsNullToken(m_tkParamDef))
764 RuntimeType attributeRuntimeType = attributeType.UnderlyingSystemType as RuntimeType;
766 if (attributeRuntimeType == null)
767 throw new ArgumentException(Environment.GetResourceString("Arg_MustBeType"), "attributeType");
769 return CustomAttribute.IsDefined(this, attributeRuntimeType);
772 public override IList<CustomAttributeData> GetCustomAttributesData()
774 return CustomAttributeData.GetCustomAttributesInternal(this);
779 #region Remoting Cache
780 private RemotingParameterCachedData m_cachedData;
782 internal RemotingParameterCachedData RemotingCache
786 // This grabs an internal copy of m_cachedData and uses
787 // that instead of looking at m_cachedData directly because
788 // the cache may get cleared asynchronously. This prevents
789 // us from having to take a lock.
790 RemotingParameterCachedData cache = m_cachedData;
793 cache = new RemotingParameterCachedData(this);
794 RemotingParameterCachedData ret = Interlocked.CompareExchange(ref m_cachedData, cache, null);
802 #endif //FEATURE_REMOTING