2014-08-13 10:39:27 +01:00
//
2019-04-12 14:10:50 +00:00
// RuntimePropertyInfo.cs: The class used to represent Properties from the mono runtime.
2014-08-13 10:39:27 +01:00
//
// Authors:
// Paolo Molaro (lupus@ximian.com)
// Patrik Torstensson (patrik.torstensson@labs2.com)
// Marek Safar (marek.safar@gmail.com)
//
// (C) 2001 Ximian, Inc. http://www.ximian.com
// Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
// Copyright 2013 Xamarin, Inc (http://www.xamarin.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System.Collections.Generic ;
using System.Globalization ;
using System.Runtime.CompilerServices ;
using System.Runtime.InteropServices ;
using System.Runtime.Serialization ;
using System.Security ;
using System.Text ;
2015-08-26 07:17:56 -04:00
using System.Diagnostics.Contracts ;
2019-04-12 14:10:50 +00:00
using Mono ;
2014-08-13 10:39:27 +01:00
namespace System.Reflection {
internal struct MonoPropertyInfo {
public Type parent ;
public Type declaring_type ;
public String name ;
public MethodInfo get_method ;
public MethodInfo set_method ;
public PropertyAttributes attrs ;
}
[Flags]
internal enum PInfo {
Attributes = 1 ,
GetMethod = 1 < < 1 ,
SetMethod = 1 < < 2 ,
ReflectedType = 1 < < 3 ,
DeclaringType = 1 < < 4 ,
Name = 1 < < 5
}
internal delegate object GetterAdapter ( object _this ) ;
internal delegate R Getter < T , R > ( T _this ) ;
2019-04-12 14:10:50 +00:00
[Serializable]
[StructLayout (LayoutKind.Sequential)]
internal class RuntimePropertyInfo : PropertyInfo
#if ! NETCORE
, ISerializable
#endif
2015-08-26 07:17:56 -04:00
{
2019-04-12 14:10:50 +00:00
#pragma warning disable 649
internal IntPtr klass ;
internal IntPtr prop ;
MonoPropertyInfo info ;
PInfo cached ;
GetterAdapter cached_getter ;
#pragma warning restore 649
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal static extern void get_property_info ( RuntimePropertyInfo prop , ref MonoPropertyInfo info ,
PInfo req_info ) ;
[MethodImplAttribute (MethodImplOptions.InternalCall)]
internal static extern Type [ ] GetTypeModifiers ( RuntimePropertyInfo prop , bool optional ) ;
[MethodImplAttribute (MethodImplOptions.InternalCall)]
internal static extern object get_default_value ( RuntimePropertyInfo prop ) ;
2019-07-26 19:53:28 +00:00
#if NETCORE
2015-08-26 07:17:56 -04:00
internal BindingFlags BindingFlags {
get {
2019-07-26 19:53:28 +00:00
CachePropertyInfo ( PInfo . GetMethod | PInfo . SetMethod ) ;
bool isPublic = info . set_method ? . IsPublic = = true | | info . get_method ? . IsPublic = = true ;
bool isStatic = info . set_method ? . IsStatic = = true | | info . get_method ? . IsStatic = = true ;
bool isInherited = DeclaringType ! = ReflectedType ;
return FilterPreCalculate ( isPublic , isInherited , isStatic ) ;
2015-08-26 07:17:56 -04:00
}
}
2019-07-26 19:53:28 +00:00
// Copied from https://github.com/dotnet/coreclr/blob/7a24a538cd265993e5864179f51781398c28ecdf/src/System.Private.CoreLib/src/System/RtType.cs#L2022
static BindingFlags FilterPreCalculate ( bool isPublic , bool isInherited , bool isStatic )
{
BindingFlags bindingFlags = isPublic ? BindingFlags . Public : BindingFlags . NonPublic ;
if ( isInherited ) {
// We arrange things so the DeclaredOnly flag means "include inherited members"
bindingFlags | = BindingFlags . DeclaredOnly ;
if ( isStatic )
bindingFlags | = BindingFlags . Static | BindingFlags . FlattenHierarchy ;
else
bindingFlags | = BindingFlags . Instance ;
}
else {
if ( isStatic )
bindingFlags | = BindingFlags . Static ;
else
bindingFlags | = BindingFlags . Instance ;
}
return bindingFlags ;
}
#else
internal BindingFlags BindingFlags = > 0 ;
#endif
2015-08-26 07:17:56 -04:00
public override Module Module {
get {
return GetRuntimeModule ( ) ;
}
}
internal RuntimeType GetDeclaringTypeInternal ( )
{
return ( RuntimeType ) DeclaringType ;
}
RuntimeType ReflectedTypeInternal {
get {
return ( RuntimeType ) ReflectedType ;
}
}
internal RuntimeModule GetRuntimeModule ( )
{
return GetDeclaringTypeInternal ( ) . GetRuntimeModule ( ) ;
}
#region Object Overrides
public override String ToString ( )
{
return FormatNameAndSig ( false ) ;
}
private string FormatNameAndSig ( bool serialization )
{
StringBuilder sbName = new StringBuilder ( PropertyType . FormatTypeName ( serialization ) ) ;
sbName . Append ( " " ) ;
sbName . Append ( Name ) ;
var pi = GetIndexParameters ( ) ;
if ( pi . Length > 0 ) {
sbName . Append ( " [" ) ;
2019-04-12 14:10:50 +00:00
RuntimeParameterInfo . FormatParameters ( sbName , pi , 0 , serialization ) ;
2015-08-26 07:17:56 -04:00
sbName . Append ( "]" ) ;
}
return sbName . ToString ( ) ;
}
#endregion
2019-04-12 14:10:50 +00:00
#if ! NETCORE
2015-08-26 07:17:56 -04:00
#region ISerializable Implementation
public void GetObjectData ( SerializationInfo info , StreamingContext context )
{
if ( info = = null )
throw new ArgumentNullException ( "info" ) ;
Contract . EndContractBlock ( ) ;
MemberInfoSerializationHolder . GetSerializationInfo (
info ,
Name ,
ReflectedTypeInternal ,
ToString ( ) ,
SerializationToString ( ) ,
MemberTypes . Property ,
null ) ;
}
internal string SerializationToString ( )
{
return FormatNameAndSig ( true ) ;
}
#endregion
2019-04-12 14:10:50 +00:00
#endif
2014-08-13 10:39:27 +01:00
void CachePropertyInfo ( PInfo flags )
{
if ( ( cached & flags ) ! = flags ) {
2019-04-12 14:10:50 +00:00
get_property_info ( this , ref info , flags ) ;
2014-08-13 10:39:27 +01:00
cached | = flags ;
}
}
public override PropertyAttributes Attributes {
get {
CachePropertyInfo ( PInfo . Attributes ) ;
return info . attrs ;
}
}
public override bool CanRead {
get {
CachePropertyInfo ( PInfo . GetMethod ) ;
return ( info . get_method ! = null ) ;
}
}
public override bool CanWrite {
get {
CachePropertyInfo ( PInfo . SetMethod ) ;
return ( info . set_method ! = null ) ;
}
}
public override Type PropertyType {
get {
CachePropertyInfo ( PInfo . GetMethod | PInfo . SetMethod ) ;
if ( info . get_method ! = null ) {
return info . get_method . ReturnType ;
} else {
ParameterInfo [ ] parameters = info . set_method . GetParametersInternal ( ) ;
return parameters [ parameters . Length - 1 ] . ParameterType ;
}
}
}
public override Type ReflectedType {
get {
CachePropertyInfo ( PInfo . ReflectedType ) ;
return info . parent ;
}
}
public override Type DeclaringType {
get {
CachePropertyInfo ( PInfo . DeclaringType ) ;
return info . declaring_type ;
}
}
public override string Name {
get {
CachePropertyInfo ( PInfo . Name ) ;
return info . name ;
}
}
public override MethodInfo [ ] GetAccessors ( bool nonPublic )
{
int nget = 0 ;
int nset = 0 ;
CachePropertyInfo ( PInfo . GetMethod | PInfo . SetMethod ) ;
if ( info . set_method ! = null & & ( nonPublic | | info . set_method . IsPublic ) )
nset = 1 ;
if ( info . get_method ! = null & & ( nonPublic | | info . get_method . IsPublic ) )
nget = 1 ;
MethodInfo [ ] res = new MethodInfo [ nget + nset ] ;
int n = 0 ;
if ( nset ! = 0 )
res [ n + + ] = info . set_method ;
if ( nget ! = 0 )
res [ n + + ] = info . get_method ;
return res ;
}
public override MethodInfo GetGetMethod ( bool nonPublic )
{
CachePropertyInfo ( PInfo . GetMethod ) ;
if ( info . get_method ! = null & & ( nonPublic | | info . get_method . IsPublic ) )
return info . get_method ;
else
return null ;
}
public override ParameterInfo [ ] GetIndexParameters ( )
{
CachePropertyInfo ( PInfo . GetMethod | PInfo . SetMethod ) ;
ParameterInfo [ ] src ;
int length ;
if ( info . get_method ! = null ) {
src = info . get_method . GetParametersInternal ( ) ;
length = src . Length ;
} else if ( info . set_method ! = null ) {
src = info . set_method . GetParametersInternal ( ) ;
length = src . Length - 1 ;
} else
return EmptyArray < ParameterInfo > . Value ;
var dest = new ParameterInfo [ length ] ;
for ( int i = 0 ; i < length ; + + i ) {
2019-04-12 14:10:50 +00:00
dest [ i ] = RuntimeParameterInfo . New ( src [ i ] , this ) ;
2014-08-13 10:39:27 +01:00
}
return dest ;
}
public override MethodInfo GetSetMethod ( bool nonPublic )
{
CachePropertyInfo ( PInfo . SetMethod ) ;
if ( info . set_method ! = null & & ( nonPublic | | info . set_method . IsPublic ) )
return info . set_method ;
else
return null ;
}
/*TODO verify for attribute based default values, just like ParameterInfo*/
public override object GetConstantValue ( )
{
2019-04-12 14:10:50 +00:00
return get_default_value ( this ) ;
2014-08-13 10:39:27 +01:00
}
public override object GetRawConstantValue ( ) {
2019-04-12 14:10:50 +00:00
return get_default_value ( this ) ;
2014-08-13 10:39:27 +01:00
}
// According to MSDN the inherit parameter is ignored here and
// the behavior always defaults to inherit = false
//
public override bool IsDefined ( Type attributeType , bool inherit )
{
return MonoCustomAttrs . IsDefined ( this , attributeType , false ) ;
}
public override object [ ] GetCustomAttributes ( bool inherit )
{
return MonoCustomAttrs . GetCustomAttributes ( this , false ) ;
}
public override object [ ] GetCustomAttributes ( Type attributeType , bool inherit )
{
return MonoCustomAttrs . GetCustomAttributes ( this , attributeType , false ) ;
}
delegate object GetterAdapter ( object _this ) ;
delegate R Getter < T , R > ( T _this ) ;
delegate R StaticGetter < R > ( ) ;
#pragma warning disable 169
// Used via reflection
static object GetterAdapterFrame < T , R > ( Getter < T , R > getter , object obj )
{
return getter ( ( T ) obj ) ;
}
static object StaticGetterAdapterFrame < R > ( StaticGetter < R > getter , object obj )
{
return getter ( ) ;
}
#pragma warning restore 169
/ *
* The idea behing this optimization is to use a pair of delegates to simulate the same effect of doing a reflection call .
* The first delegate cast the this argument to the right type and the second does points to the target method .
* /
static GetterAdapter CreateGetterDelegate ( MethodInfo method )
{
Type [ ] typeVector ;
Type getterType ;
object getterDelegate ;
MethodInfo adapterFrame ;
Type getterDelegateType ;
string frameName ;
if ( method . IsStatic ) {
typeVector = new Type [ ] { method . ReturnType } ;
getterDelegateType = typeof ( StaticGetter < > ) ;
frameName = "StaticGetterAdapterFrame" ;
} else {
typeVector = new Type [ ] { method . DeclaringType , method . ReturnType } ;
getterDelegateType = typeof ( Getter < , > ) ;
frameName = "GetterAdapterFrame" ;
}
getterType = getterDelegateType . MakeGenericType ( typeVector ) ;
getterDelegate = Delegate . CreateDelegate ( getterType , method ) ;
2019-04-12 14:10:50 +00:00
adapterFrame = typeof ( RuntimePropertyInfo ) . GetMethod ( frameName , BindingFlags . Static | BindingFlags . NonPublic ) ;
2014-08-13 10:39:27 +01:00
adapterFrame = adapterFrame . MakeGenericMethod ( typeVector ) ;
return ( GetterAdapter ) Delegate . CreateDelegate ( typeof ( GetterAdapter ) , getterDelegate , adapterFrame , true ) ;
}
public override object GetValue ( object obj , object [ ] index )
{
if ( index = = null | | index . Length = = 0 ) {
/*FIXME we should check if the number of arguments matches the expected one, otherwise the error message will be pretty criptic.*/
#if ! FULL_AOT_RUNTIME
if ( cached_getter = = null ) {
MethodInfo method = GetGetMethod ( true ) ;
2019-02-04 20:11:37 +00:00
if ( method = = null )
throw new ArgumentException ( $"Get Method not found for '{Name}'" ) ;
2019-07-26 19:53:28 +00:00
if ( ! DeclaringType . IsValueType & & ! PropertyType . IsByRef & & ! method . ContainsGenericParameters ) { //FIXME find a way to build an invoke delegate for value types.
2014-08-13 10:39:27 +01:00
cached_getter = CreateGetterDelegate ( method ) ;
// The try-catch preserves the .Invoke () behaviour
try {
return cached_getter ( obj ) ;
} catch ( Exception ex ) {
throw new TargetInvocationException ( ex ) ;
}
}
} else {
try {
return cached_getter ( obj ) ;
} catch ( Exception ex ) {
throw new TargetInvocationException ( ex ) ;
}
}
#endif
}
return GetValue ( obj , BindingFlags . Default , null , index , null ) ;
}
public override object GetValue ( object obj , BindingFlags invokeAttr , Binder binder , object [ ] index , CultureInfo culture )
{
object ret = null ;
MethodInfo method = GetGetMethod ( true ) ;
if ( method = = null )
2019-02-04 20:11:37 +00:00
throw new ArgumentException ( $"Get Method not found for '{Name}'" ) ;
2014-08-13 10:39:27 +01:00
try {
if ( index = = null | | index . Length = = 0 )
ret = method . Invoke ( obj , invokeAttr , binder , null , culture ) ;
else
ret = method . Invoke ( obj , invokeAttr , binder , index , culture ) ;
}
catch ( SecurityException se ) {
throw new TargetInvocationException ( se ) ;
}
return ret ;
}
public override void SetValue ( object obj , object value , BindingFlags invokeAttr , Binder binder , object [ ] index , CultureInfo culture )
{
MethodInfo method = GetSetMethod ( true ) ;
if ( method = = null )
throw new ArgumentException ( "Set Method not found for '" + Name + "'" ) ;
object [ ] parms ;
if ( index = = null | | index . Length = = 0 )
parms = new object [ ] { value } ;
else {
int ilen = index . Length ;
parms = new object [ ilen + 1 ] ;
index . CopyTo ( parms , 0 ) ;
parms [ ilen ] = value ;
}
method . Invoke ( obj , invokeAttr , binder , parms , culture ) ;
}
2019-04-12 14:10:50 +00:00
public override Type [ ] GetOptionalCustomModifiers ( ) = > GetCustomModifiers ( true ) ;
2014-08-13 10:39:27 +01:00
2019-04-12 14:10:50 +00:00
public override Type [ ] GetRequiredCustomModifiers ( ) = > GetCustomModifiers ( false ) ;
private Type [ ] GetCustomModifiers ( bool optional ) = > GetTypeModifiers ( this , optional ) ? ? Type . EmptyTypes ;
2014-08-13 10:39:27 +01:00
public override IList < CustomAttributeData > GetCustomAttributesData ( ) {
return CustomAttributeData . GetCustomAttributes ( this ) ;
}
2019-02-04 20:11:37 +00:00
2019-04-12 14:10:50 +00:00
public sealed override bool HasSameMetadataDefinitionAs ( MemberInfo other ) = > HasSameMetadataDefinitionAsCore < RuntimePropertyInfo > ( other ) ;
2019-02-04 20:11:37 +00:00
public override int MetadataToken {
get {
return get_metadata_token ( this ) ;
}
}
[MethodImplAttribute (MethodImplOptions.InternalCall)]
2019-04-12 14:10:50 +00:00
internal static extern int get_metadata_token ( RuntimePropertyInfo monoProperty ) ;
2019-02-04 20:11:37 +00:00
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private static extern PropertyInfo internal_from_handle_type ( IntPtr event_handle , IntPtr type_handle ) ;
2019-04-12 14:10:50 +00:00
internal static PropertyInfo GetPropertyFromHandle ( RuntimePropertyHandle handle , RuntimeTypeHandle reflectedType )
2019-02-04 20:11:37 +00:00
{
if ( handle . Value = = IntPtr . Zero )
throw new ArgumentException ( "The handle is invalid." ) ;
PropertyInfo pi = internal_from_handle_type ( handle . Value , reflectedType . Value ) ;
if ( pi = = null )
throw new ArgumentException ( "The property handle and the type handle are incompatible." ) ;
return pi ;
}
2014-08-13 10:39:27 +01:00
}
}