/* Copyright (C) 2014-2019 de4dot@gmail.com This file is part of dnSpy dnSpy is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. dnSpy is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with dnSpy. If not, see . */ using System; using System.Collections.ObjectModel; namespace dnSpy.Debugger.DotNet.Metadata { /// /// A .NET property /// public abstract class DmdPropertyInfo : DmdMemberInfo, IEquatable { /// /// Gets the AppDomain /// public sealed override DmdAppDomain AppDomain => DeclaringType!.AppDomain; /// /// Gets the member type /// public sealed override DmdMemberTypes MemberType => DmdMemberTypes.Property; /// /// Gets the property type /// public abstract DmdType PropertyType { get; } /// /// Gets the property attributes /// public abstract DmdPropertyAttributes Attributes { get; } #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member public bool IsSpecialName => (Attributes & DmdPropertyAttributes.SpecialName) != 0; public bool IsRTSpecialName => (Attributes & DmdPropertyAttributes.RTSpecialName) != 0; public bool HasDefault => (Attributes & DmdPropertyAttributes.HasDefault) != 0; #pragma warning restore CS1591 // Missing XML comment for publicly visible type or member /// /// true if the property can be read /// public bool CanRead => GetMethod is not null; /// /// true if the property can be written to /// public bool CanWrite => SetMethod is not null; /// /// Resolves a property reference /// /// true to throw if it doesn't exist, false to return null if it doesn't exist /// public sealed override DmdMemberInfo? ResolveMember(bool throwOnError) => this; /// /// Returns false since there are no property references /// public sealed override bool IsMetadataReference => false; /// /// Gets the constant stored in metadata /// /// public abstract object? GetRawConstantValue(); /// /// Gets all accessors /// /// true to include all accessors, false to only include public accessors /// public DmdMethodInfo[] GetAccessors(bool nonPublic) => GetAccessors(nonPublic ? DmdGetAccessorOptions.NonPublic : DmdGetAccessorOptions.None); /// /// Gets all accessors /// /// Options /// public abstract DmdMethodInfo[] GetAccessors(DmdGetAccessorOptions options); /// /// Gets the get method /// /// true to return any get method, false to only return a public get method /// public DmdMethodInfo? GetGetMethod(bool nonPublic) => GetGetMethod(nonPublic ? DmdGetAccessorOptions.NonPublic : DmdGetAccessorOptions.None); /// /// Gets the get method /// /// Options /// public abstract DmdMethodInfo? GetGetMethod(DmdGetAccessorOptions options); /// /// Gets the set method /// /// true to return any set method, false to only return a public set method /// public DmdMethodInfo? GetSetMethod(bool nonPublic) => GetSetMethod(nonPublic ? DmdGetAccessorOptions.NonPublic : DmdGetAccessorOptions.None); /// /// Gets the set method /// /// Options /// public abstract DmdMethodInfo? GetSetMethod(DmdGetAccessorOptions options); /// /// Gets the index parameters /// /// public abstract ReadOnlyCollection GetIndexParameters(); /// /// Gets all required custom modifiers /// /// public DmdType[] GetRequiredCustomModifiers() => DmdCustomModifierUtilities.GetModifiers(GetCustomModifiers(), requiredModifiers: true); /// /// Gets all optional custom modifiers /// /// public DmdType[] GetOptionalCustomModifiers() => DmdCustomModifierUtilities.GetModifiers(GetCustomModifiers(), requiredModifiers: false); /// /// Gets all custom modifiers /// /// public ReadOnlyCollection GetCustomModifiers() => PropertyType.GetCustomModifiers(); /// /// Gets all public accessors /// /// public DmdMethodInfo[] GetAccessors() => GetAccessors(nonPublic: false); /// /// Gets the get method /// public DmdMethodInfo? GetMethod => GetGetMethod(nonPublic: true); /// /// Gets the set method /// public DmdMethodInfo? SetMethod => GetSetMethod(nonPublic: true); /// /// Gets the public get method /// /// public DmdMethodInfo? GetGetMethod() => GetGetMethod(nonPublic: false); /// /// Gets the public set method /// /// public DmdMethodInfo? GetSetMethod() => GetSetMethod(nonPublic: false); /// /// Gets the method signature /// /// public abstract DmdMethodSignature GetMethodSignature(); /// /// Gets the property value /// /// Evaluation context /// Instance or null if it's a static property /// public object? GetValue(object? context, object? obj) => GetValue(context, obj, null); /// /// Gets the property value /// /// Evaluation context /// Instance or null if it's a static property /// Property indexes /// public object? GetValue(object? context, object? obj, object?[]? index) => GetValue(context, obj, DmdBindingFlags.Instance | DmdBindingFlags.Static | DmdBindingFlags.Public | DmdBindingFlags.NonPublic, index); /// /// Gets the property value /// /// Evaluation context /// Instance or null if it's a static property /// Binding flags /// Property indexes /// public object? GetValue(object? context, object? obj, DmdBindingFlags invokeAttr, object?[]? index) { var method = GetGetMethod(nonPublic: true); if (method is null) throw new ArgumentException(); return method.Invoke(context, obj, invokeAttr, index); } /// /// Writes a new property value /// /// Evaluation context /// Instance or null if it's a static property /// New value public void SetValue(object? context, object? obj, object? value) => SetValue(context, obj, value, null); /// /// Writes a new property value /// /// Evaluation context /// Instance or null if it's a static property /// New value /// Property indexes public void SetValue(object? context, object? obj, object? value, object?[]? index) => SetValue(context, obj, value, DmdBindingFlags.Instance | DmdBindingFlags.Static | DmdBindingFlags.Public | DmdBindingFlags.NonPublic, index); /// /// Writes a new property value /// /// Evaluation context /// Instance or null if it's a static property /// New value /// Binding flags /// Property indexes public void SetValue(object? context, object? obj, object? value, DmdBindingFlags invokeAttr, object?[]? index) { var method = GetSetMethod(nonPublic: true); if (method is null) throw new ArgumentException(); object?[] parameters; if (index is null || index.Length == 0) parameters = new[] { value }; else { parameters = new object[index.Length + 1]; int i = 0; for (; i < index.Length; i++) parameters[i] = index[i]; parameters[i] = value; } method.Invoke(context, obj, invokeAttr, parameters); } #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member public static bool operator ==(DmdPropertyInfo? left, DmdPropertyInfo? right) => DmdMemberInfoEqualityComparer.DefaultMember.Equals(left, right); public static bool operator !=(DmdPropertyInfo? left, DmdPropertyInfo? right) => !DmdMemberInfoEqualityComparer.DefaultMember.Equals(left, right); #pragma warning restore CS1591 // Missing XML comment for publicly visible type or member /// /// Equals() /// /// /// public bool Equals(DmdPropertyInfo? other) => DmdMemberInfoEqualityComparer.DefaultMember.Equals(this, other); /// /// Equals() /// /// /// public override bool Equals(object? obj) => Equals(obj as DmdPropertyInfo); /// /// GetHashCode() /// /// public override int GetHashCode() => DmdMemberInfoEqualityComparer.DefaultMember.GetHashCode(this); /// /// ToString() /// /// public sealed override string? ToString() => DmdMemberFormatter.Format(this); } }