a575963da9
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
641 lines
18 KiB
C#
641 lines
18 KiB
C#
//
|
|
// MonoMethod.cs: The class used to represent methods from the mono runtime.
|
|
//
|
|
// Authors:
|
|
// Paolo Molaro (lupus@ximian.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 (C) 2012 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;
|
|
#if !FULL_AOT_RUNTIME
|
|
using System.Reflection.Emit;
|
|
#endif
|
|
using System.Security;
|
|
using System.Threading;
|
|
using System.Text;
|
|
using System.Diagnostics;
|
|
|
|
namespace System.Reflection {
|
|
|
|
internal struct MonoMethodInfo
|
|
{
|
|
#pragma warning disable 649
|
|
private Type parent;
|
|
private Type ret;
|
|
internal MethodAttributes attrs;
|
|
internal MethodImplAttributes iattrs;
|
|
private CallingConventions callconv;
|
|
#pragma warning restore 649
|
|
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
static extern void get_method_info (IntPtr handle, out MonoMethodInfo info);
|
|
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
static extern int get_method_attributes (IntPtr handle);
|
|
|
|
internal static MonoMethodInfo GetMethodInfo (IntPtr handle)
|
|
{
|
|
MonoMethodInfo info;
|
|
MonoMethodInfo.get_method_info (handle, out info);
|
|
return info;
|
|
}
|
|
|
|
internal static Type GetDeclaringType (IntPtr handle)
|
|
{
|
|
return GetMethodInfo (handle).parent;
|
|
}
|
|
|
|
internal static Type GetReturnType (IntPtr handle)
|
|
{
|
|
return GetMethodInfo (handle).ret;
|
|
}
|
|
|
|
internal static MethodAttributes GetAttributes (IntPtr handle)
|
|
{
|
|
return (MethodAttributes)get_method_attributes (handle);
|
|
}
|
|
|
|
internal static CallingConventions GetCallingConvention (IntPtr handle)
|
|
{
|
|
return GetMethodInfo (handle).callconv;
|
|
}
|
|
|
|
internal static MethodImplAttributes GetMethodImplementationFlags (IntPtr handle)
|
|
{
|
|
return GetMethodInfo (handle).iattrs;
|
|
}
|
|
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
static extern ParameterInfo[] get_parameter_info (IntPtr handle, MemberInfo member);
|
|
|
|
static internal ParameterInfo[] GetParametersInfo (IntPtr handle, MemberInfo member)
|
|
{
|
|
return get_parameter_info (handle, member);
|
|
}
|
|
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
static extern MarshalAsAttribute get_retval_marshal (IntPtr handle);
|
|
|
|
static internal ParameterInfo GetReturnParameterInfo (MonoMethod method)
|
|
{
|
|
return ParameterInfo.New (GetReturnType (method.mhandle), method, get_retval_marshal (method.mhandle));
|
|
}
|
|
};
|
|
|
|
/*
|
|
* Note: most of this class needs to be duplicated for the contructor, since
|
|
* the .NET reflection class hierarchy is so broken.
|
|
*/
|
|
[Serializable()]
|
|
[StructLayout (LayoutKind.Sequential)]
|
|
internal class MonoMethod : MethodInfo, ISerializable
|
|
{
|
|
#pragma warning disable 649
|
|
internal IntPtr mhandle;
|
|
string name;
|
|
Type reftype;
|
|
#pragma warning restore 649
|
|
|
|
internal MonoMethod () {
|
|
}
|
|
|
|
internal MonoMethod (RuntimeMethodHandle mhandle) {
|
|
this.mhandle = mhandle.Value;
|
|
}
|
|
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
internal static extern string get_name (MethodBase method);
|
|
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
internal static extern MonoMethod get_base_method (MonoMethod method, bool definition);
|
|
|
|
public override MethodInfo GetBaseDefinition ()
|
|
{
|
|
return get_base_method (this, true);
|
|
}
|
|
|
|
internal override MethodInfo GetBaseMethod ()
|
|
{
|
|
return get_base_method (this, false);
|
|
}
|
|
|
|
public override ParameterInfo ReturnParameter {
|
|
get {
|
|
return MonoMethodInfo.GetReturnParameterInfo (this);
|
|
}
|
|
}
|
|
|
|
public override Type ReturnType {
|
|
get {
|
|
return MonoMethodInfo.GetReturnType (mhandle);
|
|
}
|
|
}
|
|
public override ICustomAttributeProvider ReturnTypeCustomAttributes {
|
|
get {
|
|
return MonoMethodInfo.GetReturnParameterInfo (this);
|
|
}
|
|
}
|
|
|
|
public override MethodImplAttributes GetMethodImplementationFlags ()
|
|
{
|
|
return MonoMethodInfo.GetMethodImplementationFlags (mhandle);
|
|
}
|
|
|
|
public override ParameterInfo[] GetParameters ()
|
|
{
|
|
var src = MonoMethodInfo.GetParametersInfo (mhandle, this);
|
|
if (src.Length == 0)
|
|
return src;
|
|
|
|
// Have to clone because GetParametersInfo icall returns cached value
|
|
var dest = new ParameterInfo [src.Length];
|
|
Array.FastCopy (src, 0, dest, 0, src.Length);
|
|
return dest;
|
|
}
|
|
|
|
internal override ParameterInfo[] GetParametersInternal ()
|
|
{
|
|
return MonoMethodInfo.GetParametersInfo (mhandle, this);
|
|
}
|
|
|
|
internal override int GetParametersCount ()
|
|
{
|
|
return MonoMethodInfo.GetParametersInfo (mhandle, this).Length;
|
|
}
|
|
|
|
/*
|
|
* InternalInvoke() receives the parameters correctly converted by the
|
|
* binder to match the types of the method signature.
|
|
*/
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
internal extern Object InternalInvoke (Object obj, Object[] parameters, out Exception exc);
|
|
|
|
[DebuggerHidden]
|
|
[DebuggerStepThrough]
|
|
public override Object Invoke (Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
|
|
{
|
|
if (binder == null)
|
|
binder = Binder.DefaultBinder;
|
|
|
|
/*Avoid allocating an array every time*/
|
|
ParameterInfo[] pinfo = GetParametersInternal ();
|
|
binder.ConvertValues (parameters, pinfo, culture, (invokeAttr & BindingFlags.ExactBinding) != 0);
|
|
|
|
#if !NET_2_1
|
|
if (SecurityManager.SecurityEnabled) {
|
|
// sadly Attributes doesn't tell us which kind of security action this is so
|
|
// we must do it the hard way - and it also means that we can skip calling
|
|
// Attribute (which is another an icall)
|
|
SecurityManager.ReflectedLinkDemandInvoke (this);
|
|
}
|
|
#endif
|
|
|
|
if (ContainsGenericParameters)
|
|
throw new InvalidOperationException ("Late bound operations cannot be performed on types or methods for which ContainsGenericParameters is true.");
|
|
|
|
Exception exc;
|
|
object o = null;
|
|
|
|
try {
|
|
// The ex argument is used to distinguish exceptions thrown by the icall
|
|
// from the exceptions thrown by the called method (which need to be
|
|
// wrapped in TargetInvocationException).
|
|
o = InternalInvoke (obj, parameters, out exc);
|
|
} catch (ThreadAbortException) {
|
|
throw;
|
|
#if NET_2_1
|
|
} catch (MethodAccessException) {
|
|
throw;
|
|
#endif
|
|
} catch (Exception e) {
|
|
throw new TargetInvocationException (e);
|
|
}
|
|
|
|
if (exc != null)
|
|
throw exc;
|
|
return o;
|
|
}
|
|
|
|
public override RuntimeMethodHandle MethodHandle {
|
|
get {
|
|
return new RuntimeMethodHandle (mhandle);
|
|
}
|
|
}
|
|
|
|
public override MethodAttributes Attributes {
|
|
get {
|
|
return MonoMethodInfo.GetAttributes (mhandle);
|
|
}
|
|
}
|
|
|
|
public override CallingConventions CallingConvention {
|
|
get {
|
|
return MonoMethodInfo.GetCallingConvention (mhandle);
|
|
}
|
|
}
|
|
|
|
public override Type ReflectedType {
|
|
get {
|
|
return reftype;
|
|
}
|
|
}
|
|
public override Type DeclaringType {
|
|
get {
|
|
return MonoMethodInfo.GetDeclaringType (mhandle);
|
|
}
|
|
}
|
|
public override string Name {
|
|
get {
|
|
if (name != null)
|
|
return name;
|
|
return get_name (this);
|
|
}
|
|
}
|
|
|
|
public override bool IsDefined (Type attributeType, bool inherit) {
|
|
return MonoCustomAttrs.IsDefined (this, attributeType, inherit);
|
|
}
|
|
|
|
public override object[] GetCustomAttributes( bool inherit) {
|
|
return MonoCustomAttrs.GetCustomAttributes (this, inherit);
|
|
}
|
|
public override object[] GetCustomAttributes( Type attributeType, bool inherit) {
|
|
return MonoCustomAttrs.GetCustomAttributes (this, attributeType, inherit);
|
|
}
|
|
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
internal static extern DllImportAttribute GetDllImportAttribute (IntPtr mhandle);
|
|
|
|
internal object[] GetPseudoCustomAttributes ()
|
|
{
|
|
int count = 0;
|
|
|
|
/* MS.NET doesn't report MethodImplAttribute */
|
|
|
|
MonoMethodInfo info = MonoMethodInfo.GetMethodInfo (mhandle);
|
|
if ((info.iattrs & MethodImplAttributes.PreserveSig) != 0)
|
|
count ++;
|
|
if ((info.attrs & MethodAttributes.PinvokeImpl) != 0)
|
|
count ++;
|
|
|
|
if (count == 0)
|
|
return null;
|
|
object[] attrs = new object [count];
|
|
count = 0;
|
|
|
|
if ((info.iattrs & MethodImplAttributes.PreserveSig) != 0)
|
|
attrs [count ++] = new PreserveSigAttribute ();
|
|
if ((info.attrs & MethodAttributes.PinvokeImpl) != 0) {
|
|
DllImportAttribute attr = GetDllImportAttribute (mhandle);
|
|
if ((info.iattrs & MethodImplAttributes.PreserveSig) != 0)
|
|
attr.PreserveSig = true;
|
|
attrs [count ++] = attr;
|
|
}
|
|
|
|
return attrs;
|
|
}
|
|
|
|
public override string ToString () {
|
|
StringBuilder sb = new StringBuilder ();
|
|
Type retType = ReturnType;
|
|
if (Type.ShouldPrintFullName (retType))
|
|
sb.Append (retType.ToString ());
|
|
else
|
|
sb.Append (retType.Name);
|
|
sb.Append (" ");
|
|
sb.Append (Name);
|
|
if (IsGenericMethod) {
|
|
Type[] gen_params = GetGenericArguments ();
|
|
sb.Append ("[");
|
|
for (int j = 0; j < gen_params.Length; j++) {
|
|
if (j > 0)
|
|
sb.Append (",");
|
|
sb.Append (gen_params [j].Name);
|
|
}
|
|
sb.Append ("]");
|
|
}
|
|
sb.Append ("(");
|
|
|
|
var p = GetParametersInternal ();
|
|
ParameterInfo.FormatParameters (sb, p);
|
|
|
|
if ((CallingConvention & CallingConventions.VarArgs) != 0) {
|
|
if (p.Length > 0)
|
|
sb.Append (", ");
|
|
sb.Append ("...");
|
|
}
|
|
|
|
sb.Append (")");
|
|
return sb.ToString ();
|
|
}
|
|
|
|
|
|
// ISerializable
|
|
public void GetObjectData(SerializationInfo info, StreamingContext context)
|
|
{
|
|
Type[] genericArguments = IsGenericMethod && !IsGenericMethodDefinition
|
|
? GetGenericArguments () : null;
|
|
MemberInfoSerializationHolder.Serialize ( info, Name, ReflectedType, ToString(), MemberTypes.Method, genericArguments);
|
|
}
|
|
|
|
public override MethodInfo MakeGenericMethod (Type [] methodInstantiation)
|
|
{
|
|
if (methodInstantiation == null)
|
|
throw new ArgumentNullException ("methodInstantiation");
|
|
|
|
if (!IsGenericMethodDefinition)
|
|
throw new InvalidOperationException ("not a generic method definition");
|
|
|
|
/*FIXME add GetGenericArgumentsLength() internal vcall to speed this up*/
|
|
if (GetGenericArguments ().Length != methodInstantiation.Length)
|
|
throw new ArgumentException ("Incorrect length");
|
|
|
|
bool hasUserType = false;
|
|
foreach (Type type in methodInstantiation) {
|
|
if (type == null)
|
|
throw new ArgumentNullException ();
|
|
if (!(type is MonoType))
|
|
hasUserType = true;
|
|
}
|
|
|
|
if (hasUserType)
|
|
#if FULL_AOT_RUNTIME
|
|
throw new NotSupportedException ("User types are not supported under full aot");
|
|
#else
|
|
return new MethodOnTypeBuilderInst (this, methodInstantiation);
|
|
#endif
|
|
|
|
MethodInfo ret = MakeGenericMethod_impl (methodInstantiation);
|
|
if (ret == null)
|
|
throw new ArgumentException (String.Format ("The method has {0} generic parameter(s) but {1} generic argument(s) were provided.", GetGenericArguments ().Length, methodInstantiation.Length));
|
|
return ret;
|
|
}
|
|
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
extern MethodInfo MakeGenericMethod_impl (Type [] types);
|
|
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
public override extern Type [] GetGenericArguments ();
|
|
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
extern MethodInfo GetGenericMethodDefinition_impl ();
|
|
|
|
public override MethodInfo GetGenericMethodDefinition ()
|
|
{
|
|
MethodInfo res = GetGenericMethodDefinition_impl ();
|
|
if (res == null)
|
|
throw new InvalidOperationException ();
|
|
|
|
return res;
|
|
}
|
|
|
|
public override extern bool IsGenericMethodDefinition {
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
get;
|
|
}
|
|
|
|
public override extern bool IsGenericMethod {
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
get;
|
|
}
|
|
|
|
public override bool ContainsGenericParameters {
|
|
get {
|
|
if (IsGenericMethod) {
|
|
foreach (Type arg in GetGenericArguments ())
|
|
if (arg.ContainsGenericParameters)
|
|
return true;
|
|
}
|
|
return DeclaringType.ContainsGenericParameters;
|
|
}
|
|
}
|
|
|
|
public override MethodBody GetMethodBody () {
|
|
return GetMethodBody (mhandle);
|
|
}
|
|
|
|
#if NET_4_0
|
|
public override IList<CustomAttributeData> GetCustomAttributesData () {
|
|
return CustomAttributeData.GetCustomAttributes (this);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
[Serializable()]
|
|
[StructLayout (LayoutKind.Sequential)]
|
|
internal class MonoCMethod : ConstructorInfo, ISerializable
|
|
{
|
|
#pragma warning disable 649
|
|
internal IntPtr mhandle;
|
|
string name;
|
|
Type reftype;
|
|
#pragma warning restore 649
|
|
|
|
public override MethodImplAttributes GetMethodImplementationFlags ()
|
|
{
|
|
return MonoMethodInfo.GetMethodImplementationFlags (mhandle);
|
|
}
|
|
|
|
public override ParameterInfo[] GetParameters ()
|
|
{
|
|
return MonoMethodInfo.GetParametersInfo (mhandle, this);
|
|
}
|
|
|
|
internal override ParameterInfo[] GetParametersInternal ()
|
|
{
|
|
return MonoMethodInfo.GetParametersInfo (mhandle, this);
|
|
}
|
|
|
|
internal override int GetParametersCount ()
|
|
{
|
|
var pi = MonoMethodInfo.GetParametersInfo (mhandle, this);
|
|
return pi == null ? 0 : pi.Length;
|
|
}
|
|
|
|
/*
|
|
* InternalInvoke() receives the parameters correctly converted by the binder
|
|
* to match the types of the method signature.
|
|
*/
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
internal extern Object InternalInvoke (Object obj, Object[] parameters, out Exception exc);
|
|
|
|
[DebuggerHidden]
|
|
[DebuggerStepThrough]
|
|
public override object Invoke (object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture)
|
|
{
|
|
if (obj == null) {
|
|
if (!IsStatic)
|
|
throw new TargetException ("Instance constructor requires a target");
|
|
} else if (!DeclaringType.IsInstanceOfType (obj)) {
|
|
throw new TargetException ("Constructor does not match target type");
|
|
}
|
|
|
|
return DoInvoke (obj, invokeAttr, binder, parameters, culture);
|
|
}
|
|
|
|
object DoInvoke (object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture)
|
|
{
|
|
if (binder == null)
|
|
binder = Binder.DefaultBinder;
|
|
|
|
ParameterInfo[] pinfo = MonoMethodInfo.GetParametersInfo (mhandle, this);
|
|
|
|
binder.ConvertValues (parameters, pinfo, culture, (invokeAttr & BindingFlags.ExactBinding) != 0);
|
|
|
|
#if !NET_2_1
|
|
if (SecurityManager.SecurityEnabled) {
|
|
// sadly Attributes doesn't tell us which kind of security action this is so
|
|
// we must do it the hard way - and it also means that we can skip calling
|
|
// Attribute (which is another an icall)
|
|
SecurityManager.ReflectedLinkDemandInvoke (this);
|
|
}
|
|
#endif
|
|
|
|
if (obj == null && DeclaringType.ContainsGenericParameters)
|
|
throw new MemberAccessException ("Cannot create an instance of " + DeclaringType + " because Type.ContainsGenericParameters is true.");
|
|
|
|
if ((invokeAttr & BindingFlags.CreateInstance) != 0 && DeclaringType.IsAbstract) {
|
|
throw new MemberAccessException (String.Format ("Cannot create an instance of {0} because it is an abstract class", DeclaringType));
|
|
}
|
|
|
|
return InternalInvoke (obj, parameters);
|
|
}
|
|
|
|
public object InternalInvoke (object obj, object[] parameters)
|
|
{
|
|
Exception exc;
|
|
object o = null;
|
|
|
|
try {
|
|
o = InternalInvoke (obj, parameters, out exc);
|
|
#if NET_2_1
|
|
} catch (MethodAccessException) {
|
|
throw;
|
|
#endif
|
|
} catch (Exception e) {
|
|
throw new TargetInvocationException (e);
|
|
}
|
|
|
|
if (exc != null)
|
|
throw exc;
|
|
|
|
return obj == null ? o : null;
|
|
}
|
|
|
|
[DebuggerHidden]
|
|
[DebuggerStepThrough]
|
|
public override Object Invoke (BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
|
|
{
|
|
return DoInvoke (null, invokeAttr, binder, parameters, culture);
|
|
}
|
|
|
|
public override RuntimeMethodHandle MethodHandle {
|
|
get {
|
|
return new RuntimeMethodHandle (mhandle);
|
|
}
|
|
}
|
|
|
|
public override MethodAttributes Attributes {
|
|
get {
|
|
return MonoMethodInfo.GetAttributes (mhandle);
|
|
}
|
|
}
|
|
|
|
public override CallingConventions CallingConvention {
|
|
get {
|
|
return MonoMethodInfo.GetCallingConvention (mhandle);
|
|
}
|
|
}
|
|
|
|
public override Type ReflectedType {
|
|
get {
|
|
return reftype;
|
|
}
|
|
}
|
|
public override Type DeclaringType {
|
|
get {
|
|
return MonoMethodInfo.GetDeclaringType (mhandle);
|
|
}
|
|
}
|
|
public override string Name {
|
|
get {
|
|
if (name != null)
|
|
return name;
|
|
return MonoMethod.get_name (this);
|
|
}
|
|
}
|
|
|
|
public override bool IsDefined (Type attributeType, bool inherit) {
|
|
return MonoCustomAttrs.IsDefined (this, attributeType, inherit);
|
|
}
|
|
|
|
public override object[] GetCustomAttributes( bool inherit) {
|
|
return MonoCustomAttrs.GetCustomAttributes (this, inherit);
|
|
}
|
|
|
|
public override object[] GetCustomAttributes( Type attributeType, bool inherit) {
|
|
return MonoCustomAttrs.GetCustomAttributes (this, attributeType, inherit);
|
|
}
|
|
|
|
public override MethodBody GetMethodBody () {
|
|
return GetMethodBody (mhandle);
|
|
}
|
|
|
|
public override string ToString () {
|
|
StringBuilder sb = new StringBuilder ();
|
|
sb.Append ("Void ");
|
|
sb.Append (Name);
|
|
sb.Append ("(");
|
|
ParameterInfo[] p = GetParameters ();
|
|
for (int i = 0; i < p.Length; ++i) {
|
|
if (i > 0)
|
|
sb.Append (", ");
|
|
sb.Append (p[i].ParameterType.Name);
|
|
}
|
|
if (CallingConvention == CallingConventions.Any)
|
|
sb.Append (", ...");
|
|
sb.Append (")");
|
|
return sb.ToString ();
|
|
}
|
|
|
|
// ISerializable
|
|
public void GetObjectData(SerializationInfo info, StreamingContext context)
|
|
{
|
|
MemberInfoSerializationHolder.Serialize ( info, Name, ReflectedType, ToString(), MemberTypes.Constructor);
|
|
}
|
|
|
|
#if NET_4_0
|
|
public override IList<CustomAttributeData> GetCustomAttributesData () {
|
|
return CustomAttributeData.GetCustomAttributes (this);
|
|
}
|
|
#endif
|
|
}
|
|
}
|