|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable disable
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Reflection;
using System.Security;
using System.Threading;
using System.Windows.Markup;
using System.Xaml.Schema;
using MS.Internal.Xaml.Parser;
namespace System.Xaml
{
public class XamlMember : IEquatable<XamlMember>
{
// Initialized in constructor
private string _name;
private XamlType _declaringType;
private readonly MemberType _memberType;
// Idempotent
private ThreeValuedBool _isNameValid;
// Thread safety: if setting outside ctor, do an interlocked compare against null
private MemberReflector _reflector;
/// <summary>
/// Lazy init: NullableReference.IsSet is null when not initialized
/// </summary>
private NullableReference<MemberInfo> _underlyingMember;
public XamlMember(string name, XamlType declaringType, bool isAttachable)
{
_name = name ?? throw new ArgumentNullException(nameof(name));
_declaringType = declaringType ?? throw new ArgumentNullException(nameof(declaringType));
_memberType = isAttachable ? MemberType.Attachable : MemberType.Instance;
}
// Known property
public XamlMember(PropertyInfo propertyInfo, XamlSchemaContext schemaContext)
:this(propertyInfo, schemaContext, null)
{
}
public XamlMember(PropertyInfo propertyInfo, XamlSchemaContext schemaContext, XamlMemberInvoker invoker)
: this(propertyInfo, schemaContext, invoker, new MemberReflector(false /*isEvent*/))
{
}
internal XamlMember(PropertyInfo propertyInfo, XamlSchemaContext schemaContext, XamlMemberInvoker invoker, MemberReflector reflector)
{
ArgumentNullException.ThrowIfNull(propertyInfo);
ArgumentNullException.ThrowIfNull(schemaContext);
_name = propertyInfo.Name;
_declaringType = schemaContext.GetXamlType(propertyInfo.DeclaringType);
_memberType = MemberType.Instance;
_reflector = reflector;
_reflector.Invoker = invoker;
_underlyingMember.Value = propertyInfo;
}
// Known event
public XamlMember(EventInfo eventInfo, XamlSchemaContext schemaContext)
:this(eventInfo, schemaContext, null)
{
}
public XamlMember(EventInfo eventInfo, XamlSchemaContext schemaContext, XamlMemberInvoker invoker)
:this(eventInfo, schemaContext, invoker, new MemberReflector(true /*isEvent*/))
{
}
internal XamlMember(EventInfo eventInfo, XamlSchemaContext schemaContext, XamlMemberInvoker invoker, MemberReflector reflector)
{
ArgumentNullException.ThrowIfNull(eventInfo);
ArgumentNullException.ThrowIfNull(schemaContext);
_name = eventInfo.Name;
_declaringType = schemaContext.GetXamlType(eventInfo.DeclaringType);
_memberType = MemberType.Instance;
_reflector = reflector;
_reflector.Invoker = invoker;
_underlyingMember.Value = eventInfo;
}
// Known attachable property
public XamlMember(string attachablePropertyName, MethodInfo getter, MethodInfo setter,
XamlSchemaContext schemaContext)
:this(attachablePropertyName, getter, setter, schemaContext, null)
{
}
public XamlMember(string attachablePropertyName, MethodInfo getter, MethodInfo setter,
XamlSchemaContext schemaContext, XamlMemberInvoker invoker)
:this(attachablePropertyName, getter, setter, schemaContext, invoker, new MemberReflector(getter, setter, false /*isEvent*/))
{
}
internal XamlMember(string attachablePropertyName, MethodInfo getter, MethodInfo setter,
XamlSchemaContext schemaContext, XamlMemberInvoker invoker, MemberReflector reflector)
{
ArgumentNullException.ThrowIfNull(schemaContext);
MethodInfo accessor = getter ?? setter;
if (accessor == null)
{
throw new ArgumentNullException(SR.GetterOrSetterRequired, (Exception)null);
}
_name = attachablePropertyName ?? throw new ArgumentNullException(nameof(attachablePropertyName));
ValidateGetter(getter, nameof(getter));
ValidateSetter(setter, nameof(setter));
_declaringType = schemaContext.GetXamlType(accessor.DeclaringType);
_reflector = reflector;
_memberType = MemberType.Attachable;
_reflector.Invoker = invoker;
_underlyingMember.Value = getter ?? setter;
}
// Known attachable event
public XamlMember(string attachableEventName, MethodInfo adder, XamlSchemaContext schemaContext)
:this(attachableEventName, adder, schemaContext, null)
{
}
public XamlMember(string attachableEventName, MethodInfo adder, XamlSchemaContext schemaContext,
XamlMemberInvoker invoker)
: this(attachableEventName, adder, schemaContext, invoker, new MemberReflector(null, adder, true /*isEvent*/))
{
}
internal XamlMember(string attachableEventName, MethodInfo adder, XamlSchemaContext schemaContext,
XamlMemberInvoker invoker, MemberReflector reflector)
{
ArgumentNullException.ThrowIfNull(adder);
ArgumentNullException.ThrowIfNull(schemaContext);
ValidateSetter(adder, "adder");
_name = attachableEventName ?? throw new ArgumentNullException(nameof(attachableEventName));
_declaringType = schemaContext.GetXamlType(adder.DeclaringType);
_reflector = reflector;
_memberType = MemberType.Attachable;
_reflector.Invoker = invoker;
_underlyingMember.Value = adder;
}
// Directive, only called from XamlDirective
internal XamlMember(string name, MemberReflector reflector)
{
_name = name;
_declaringType = null;
_reflector = reflector ?? MemberReflector.UnknownReflector;
_memberType = MemberType.Directive;
}
public XamlType DeclaringType { get { return _declaringType; } }
public XamlMemberInvoker Invoker
{
get
{
EnsureReflector();
if (_reflector.Invoker == null)
{
_reflector.Invoker = LookupInvoker() ?? XamlMemberInvoker.UnknownInvoker;
}
return _reflector.Invoker;
}
}
public bool IsUnknown
{
get
{
EnsureReflector();
return (_reflector.IsUnknown);
}
}
public bool IsReadPublic
{
get { return IsReadPublicIgnoringType && (_declaringType == null || _declaringType.IsPublic); }
}
public bool IsWritePublic
{
get { return IsWritePublicIgnoringType && (_declaringType == null || _declaringType.IsPublic); }
}
public string Name { get { return _name; } }
public bool IsNameValid
{
get
{
if (_isNameValid == ThreeValuedBool.NotSet)
{
_isNameValid = XamlName.IsValidXamlName(_name) ? ThreeValuedBool.True : ThreeValuedBool.False;
}
return _isNameValid == ThreeValuedBool.True;
}
}
public string PreferredXamlNamespace
{
get
{
IList<string> namespaces = GetXamlNamespaces();
if (namespaces.Count > 0)
{
return namespaces[0];
}
return null;
}
}
public XamlType TargetType
{
get
{
if (!IsAttachable)
{
return _declaringType;
}
EnsureReflector();
if (_reflector.TargetType == null)
{
if (_reflector.IsUnknown)
{
return XamlLanguage.Object;
}
_reflector.TargetType = LookupTargetType() ?? XamlLanguage.Object;
}
return _reflector.TargetType;
}
}
public XamlType Type
{
get
{
EnsureReflector();
if (_reflector.Type == null)
{
_reflector.Type = LookupType() ?? XamlLanguage.Object;
}
return _reflector.Type;
}
}
public XamlValueConverter<TypeConverter> TypeConverter
{
get
{
EnsureReflector();
if (!_reflector.TypeConverterIsSet)
{
_reflector.TypeConverter = LookupTypeConverter();
}
return _reflector.TypeConverter;
}
}
public XamlValueConverter<ValueSerializer> ValueSerializer
{
get
{
EnsureReflector();
if (!_reflector.ValueSerializerIsSet)
{
_reflector.ValueSerializer = LookupValueSerializer();
}
return _reflector.ValueSerializer;
}
}
public XamlValueConverter<XamlDeferringLoader> DeferringLoader
{
get
{
EnsureReflector();
if (!_reflector.DeferringLoaderIsSet)
{
_reflector.DeferringLoader = LookupDeferringLoader();
}
return _reflector.DeferringLoader;
}
}
public MemberInfo UnderlyingMember
{
get
{
if (!_underlyingMember.IsSet)
{
_underlyingMember.SetIfNull(LookupUnderlyingMember());
}
return _underlyingMember.Value;
}
}
/// <summary>Accesses _underlyingMember without initializing it</summary>
internal NullableReference<MemberInfo> UnderlyingMemberInternal
{
get { return _underlyingMember; }
}
public bool IsReadOnly
{
get { return GetFlag(BoolMemberBits.ReadOnly); }
}
public bool IsWriteOnly
{
get { return GetFlag(BoolMemberBits.WriteOnly); }
}
public bool IsAttachable
{
get { return _memberType == MemberType.Attachable; }
}
public bool IsEvent
{
get { return GetFlag(BoolMemberBits.Event); }
}
public bool IsDirective { get { return _memberType == MemberType.Directive; } }
public virtual IList<string> GetXamlNamespaces()
{
return DeclaringType.GetXamlNamespaces();
}
public override string ToString()
{
Debug.Assert(_declaringType != null, "XamlDirective should not call base.ToString");
return $"{_declaringType}.{Name}";
}
public IList<XamlMember> DependsOn
{
get
{
EnsureReflector();
if (_reflector.DependsOn == null)
{
_reflector.DependsOn = LookupDependsOn() ?? XamlType.EmptyList<XamlMember>.Value;
}
return _reflector.DependsOn;
}
}
public bool IsAmbient
{
get { return GetFlag(BoolMemberBits.Ambient); }
}
public DesignerSerializationVisibility SerializationVisibility
{
get
{
EnsureReflector();
if (!_reflector.DesignerSerializationVisibilityIsSet)
{
_reflector.SerializationVisibility = LookupSerializationVisibility();
}
return _reflector.SerializationVisibility ?? DesignerSerializationVisibility.Visible;
}
}
/// <summary>
/// Returns the value of the MarkupExtensionBracketCharacterAttribute set on
/// a property of a MarkupExtension as a ReadOnlyDictionary. Opening bracket is the
/// key, while the value is the closing bracket.
/// </summary>
public IReadOnlyDictionary<char,char> MarkupExtensionBracketCharacters
{
get
{
EnsureReflector();
if (!_reflector.MarkupExtensionBracketCharactersArgumentIsSet)
{
_reflector.MarkupExtensionBracketCharactersArgument = LookupMarkupExtensionBracketCharacters();
_reflector.MarkupExtensionBracketCharactersArgumentIsSet = true;
}
return _reflector.MarkupExtensionBracketCharactersArgument;
}
}
// Note: distinguishes between null (unset) and string.Empty (explicitly set to empty or null)
internal string ConstructorArgument
{
get
{
EnsureReflector();
if (!_reflector.ConstructorArgumentIsSet)
{
_reflector.ConstructorArgument = LookupConstructorArgument();
}
return _reflector.ConstructorArgument;
}
}
// Requires live reflection - only use from XOW/XOR
internal object DefaultValue
{
get
{
EnsureDefaultValue();
return _reflector.DefaultValue;
}
}
internal MethodInfo Getter
{
get
{
EnsureReflector();
if (!_reflector.GetterIsSet)
{
_reflector.Getter = LookupUnderlyingGetter();
}
return _reflector.Getter;
}
}
// Requires live reflection - only use from XOW/XOR
internal bool HasDefaultValue
{
get
{
EnsureDefaultValue();
return !_reflector.DefaultValueIsNotPresent;
}
}
internal bool HasSerializationVisibility
{
get
{
EnsureReflector();
if (!_reflector.DesignerSerializationVisibilityIsSet)
{
_reflector.SerializationVisibility = LookupSerializationVisibility();
}
return _reflector.SerializationVisibility.HasValue;
}
}
internal MethodInfo Setter
{
get
{
EnsureReflector();
if (!_reflector.SetterIsSet)
{
_reflector.Setter = LookupUnderlyingSetter();
}
return _reflector.Setter;
}
}
// Security note:
// Keep this internal so that people don't use it for real security decisions.
// This is only for convenience filtering, we still depend on the CLR for our real security.
//
// Usage note: Assumes the declaring type is visible and is public or internal
//
// Extensibility note:
// This is not overridable since it does not make sense in a non-CLR context.
internal bool IsReadVisibleTo(Assembly accessingAssembly, Type accessingType)
{
if (IsReadPublicIgnoringType)
{
return true;
}
MethodInfo getter = Getter;
if (getter != null)
{
return MemberReflector.GenericArgumentsAreVisibleTo(getter, accessingAssembly, SchemaContext) &&
(MemberReflector.IsInternalVisibleTo(getter, accessingAssembly, SchemaContext) ||
MemberReflector.IsProtectedVisibleTo(getter, accessingType, SchemaContext));
}
return false;
}
// See notes on IsReadVisibleTo
internal bool IsWriteVisibleTo(Assembly accessingAssembly, Type accessingType)
{
if (IsWritePublicIgnoringType)
{
return true;
}
MethodInfo setter = Setter;
if (setter != null)
{
return MemberReflector.GenericArgumentsAreVisibleTo(setter, accessingAssembly, SchemaContext) &&
(MemberReflector.IsInternalVisibleTo(setter, accessingAssembly, SchemaContext) ||
MemberReflector.IsProtectedVisibleTo(setter, accessingType, SchemaContext));
}
return false;
}
// If any new virtuals are added below, be sure to also override them in XamlDirective
protected virtual XamlMemberInvoker LookupInvoker()
{
if (UnderlyingMember != null)
{
return new XamlMemberInvoker(this);
}
return null;
}
protected virtual ICustomAttributeProvider LookupCustomAttributeProvider()
{
return null;
}
protected virtual XamlValueConverter<XamlDeferringLoader> LookupDeferringLoader()
{
if (AreAttributesAvailable)
{
Type[] loaderTypes = _reflector.GetAttributeTypes(typeof(XamlDeferLoadAttribute), 2);
if (loaderTypes != null)
{
return SchemaContext.GetValueConverter<XamlDeferringLoader>(loaderTypes[0], null);
}
}
if (Type != null)
{
return Type.DeferringLoader;
}
return null;
}
protected virtual IList<XamlMember> LookupDependsOn()
{
if (!AreAttributesAvailable)
{
return null;
}
List<string> doPropertyNames = _reflector.GetAllAttributeContents<string>(typeof(DependsOnAttribute));
if (doPropertyNames == null || doPropertyNames.Count == 0)
{
return null;
}
List<XamlMember> result = new List<XamlMember>();
foreach (var name in doPropertyNames)
{
XamlMember member = _declaringType.GetMember(name);
// Normally we want to throw if property lookup fails to return anything
// but here we can not throw because v3.0 does not
if (member != null)
{
result.Add(member);
}
}
return XamlType.GetReadOnly(result);
}
private DesignerSerializationVisibility? LookupSerializationVisibility()
{
DesignerSerializationVisibility? result = null;
if (AreAttributesAvailable)
{
result = _reflector.GetAttributeValue<DesignerSerializationVisibility>(
typeof(DesignerSerializationVisibilityAttribute));
}
return result;
}
protected virtual bool LookupIsAmbient()
{
if (AreAttributesAvailable)
{
return _reflector.IsAttributePresent(typeof(AmbientAttribute));
}
return GetDefaultFlag(BoolMemberBits.Ambient);
}
protected virtual bool LookupIsEvent()
{
return UnderlyingMember is EventInfo;
}
// Note: this returns whether the member itself is public or not. The visibility of the
// declaring type is considered in the IsReadPublic property, not here.
protected virtual bool LookupIsReadPublic()
{
MethodInfo getter = Getter;
if (getter != null && !getter.IsPublic)
{
return false;
}
return !IsWriteOnly;
}
protected virtual bool LookupIsReadOnly()
{
if (UnderlyingMember != null)
{
return (Setter == null);
}
return GetDefaultFlag(BoolMemberBits.ReadOnly);
}
protected virtual bool LookupIsUnknown()
{
if (_reflector != null)
{
return _reflector.IsUnknown;
}
return UnderlyingMember == null;
}
protected virtual bool LookupIsWriteOnly()
{
if (UnderlyingMember != null)
{
return (Getter == null);
}
return GetDefaultFlag(BoolMemberBits.WriteOnly);
}
// Note: this returns whether the member itself is public or not. The visibility of the
// declaring type is considered in the IsWritePublic property, not here.
protected virtual bool LookupIsWritePublic()
{
MethodInfo setter = Setter;
if (setter != null && !setter.IsPublic)
{
return false;
}
return !IsReadOnly;
}
protected virtual XamlType LookupTargetType()
{
if (IsAttachable)
{
MethodInfo accessor = UnderlyingMember as MethodInfo;
if (accessor != null)
{
ParameterInfo[] parameters = accessor.GetParameters();
if (parameters.Length > 0)
{
Type result = parameters[0].ParameterType;
return SchemaContext.GetXamlType(result);
}
}
return XamlLanguage.Object;
}
return _declaringType;
}
protected virtual XamlValueConverter<TypeConverter> LookupTypeConverter()
{
XamlValueConverter<TypeConverter> result = null;
if (AreAttributesAvailable)
{
Type converterType = _reflector.GetAttributeType(typeof(TypeConverterAttribute));
if (converterType != null)
{
result = SchemaContext.GetValueConverter<TypeConverter>(converterType, null);
}
}
if (result == null && Type != null)
{
result = Type.TypeConverter;
}
return result;
}
protected virtual XamlValueConverter<ValueSerializer> LookupValueSerializer()
{
XamlValueConverter<ValueSerializer> result = null;
if (AreAttributesAvailable)
{
Type converterType = _reflector.GetAttributeType(typeof(ValueSerializerAttribute));
if (converterType != null)
{
result = SchemaContext.GetValueConverter<ValueSerializer>(converterType, null);
}
}
if (result == null && Type != null)
{
result = Type.ValueSerializer;
}
return result;
}
/// <summary>
/// Returns the value of the MarkupExtensionBracketCharacterAttribute set on
/// a property of a MarkupExtension as a ReadOnlyDictionary. Opening bracket is the
/// key, while the value is the closing bracket.
/// </summary>
protected virtual IReadOnlyDictionary<char,char> LookupMarkupExtensionBracketCharacters()
{
if (AreAttributesAvailable)
{
IReadOnlyDictionary<char, char> bracketCharactersList = _reflector.GetBracketCharacterAttributes(typeof(MarkupExtensionBracketCharactersAttribute));
if (bracketCharactersList != null)
{
_reflector.MarkupExtensionBracketCharactersArgument = bracketCharactersList;
}
}
return _reflector.MarkupExtensionBracketCharactersArgument;
}
protected virtual XamlType LookupType()
{
Type systemType = LookupSystemType();
return (systemType != null) ? SchemaContext.GetXamlType(systemType) : null;
}
protected virtual MethodInfo LookupUnderlyingGetter()
{
EnsureReflector();
// Through normal paths, _reflector.Getter should always be null here.
// But a user could always call this protected method directly, so check just in case
if (_reflector.Getter != null)
{
return _reflector.Getter;
}
PropertyInfo pi = UnderlyingMember as PropertyInfo;
return (pi != null) ? pi.GetGetMethod(true) : null;
}
protected virtual MethodInfo LookupUnderlyingSetter()
{
EnsureReflector();
// Through normal paths, _reflector.Setter should always be null here.
// But a user could always call this protected method directly, so check just in case
if (_reflector.Setter != null)
{
return _reflector.Setter;
}
PropertyInfo pi = UnderlyingMember as PropertyInfo;
if (pi != null)
{
return pi.GetSetMethod(true);
}
else
{
EventInfo ei = UnderlyingMember as EventInfo;
return (ei != null) ? ei.GetAddMethod(true) : null;
}
}
protected virtual MemberInfo LookupUnderlyingMember()
{
// If UnderlyingMember wasn't set in ctor, this will return null.
// If UnderlyingMember was set in ctor, it shouldn't be necessary to call this
// (UnderlyingMember property will already be set), but returning the correct
// value here just in case a users calls it anyway.
return UnderlyingMemberInternal.Value;
}
private bool IsReadPublicIgnoringType
{
get
{
EnsureReflector();
bool? result = _reflector.GetFlag(BoolMemberBits.ReadPublic);
if (!result.HasValue)
{
result = LookupIsReadPublic();
_reflector.SetFlag(BoolMemberBits.ReadPublic, result.Value);
}
return result.Value;
}
}
private bool IsWritePublicIgnoringType
{
get
{
EnsureReflector();
bool? result = _reflector.GetFlag(BoolMemberBits.WritePublic);
if (!result.HasValue)
{
result = LookupIsWritePublic();
_reflector.SetFlag(BoolMemberBits.WritePublic, result.Value);
}
return result.Value;
}
}
private static void ValidateGetter(MethodInfo method, string argumentName)
{
if (method == null)
{
return;
}
if ((method.GetParameters().Length != 1) || (method.ReturnType == typeof(void)))
{
throw new ArgumentException(SR.IncorrectGetterParamNum, argumentName);
}
}
private static void ValidateSetter(MethodInfo method, string argumentName)
{
if ((method != null) && (method.GetParameters().Length != 2))
{
throw new ArgumentException(SR.IncorrectSetterParamNum, argumentName);
}
}
// This property needs to be checked before any attribute lookups on _reflector. It's not
// only informational, it also ensures that the right state is initialized.
private bool AreAttributesAvailable
{
get
{
EnsureReflector();
// Make sure that AttributeProvider is initialized
// Note: Don't short-circuit the AttributeProvider lookup, even if UnderlyingMember
// is non-null; a derived class can use AttributeProvider to override attribute lookup
// Volatile read/write of CustomAttributeProvider to make sure that threads that see
// CustomAttributeProviderIsSet == true also see the write to _reflector.UnderlyingMember
if (!_reflector.CustomAttributeProviderIsSetVolatile)
{
ICustomAttributeProvider attrProvider = LookupCustomAttributeProvider();
if (attrProvider == null)
{
// Set the member that _reflector will use. Note this also ensures that
// _underlyingMember is initialized, so it's safe to access the field directly below.
_reflector.UnderlyingMember = UnderlyingMember;
}
_reflector.SetCustomAttributeProviderVolatile(attrProvider);
}
return _reflector.CustomAttributeProvider != null || UnderlyingMemberInternal.Value != null;
}
}
private XamlSchemaContext SchemaContext { get { return _declaringType.SchemaContext; } }
private static bool GetDefaultFlag(BoolMemberBits flagBit)
{
return (BoolMemberBits.Default & flagBit) == flagBit;
}
private void CreateReflector()
{
bool isUnknown = LookupIsUnknown();
MemberReflector reflector = isUnknown ? MemberReflector.UnknownReflector : new MemberReflector();
Interlocked.CompareExchange(ref _reflector, reflector, null);
}
private void EnsureDefaultValue()
{
EnsureReflector();
if (!_reflector.DefaultValueIsSet)
{
DefaultValueAttribute defaultValueAttrib = null;
// Unlike other component-model attributes, DefaultValueAttribute is unsealed, and the
// Value property is virtual. So we cannot reliably process DefaultValueAttribute in ROL.
// The DefaultValue property is internal and is only called from XamlObjectReader, so it
// is safe to use live reflection.
if (AreAttributesAvailable)
{
ICustomAttributeProvider attributeProvider = _reflector.CustomAttributeProvider ?? UnderlyingMember;
object[] attribs = attributeProvider.GetCustomAttributes(typeof(DefaultValueAttribute), true);
if (attribs.Length > 0)
{
defaultValueAttrib = (DefaultValueAttribute)attribs[0];
}
}
if (defaultValueAttrib != null)
{
_reflector.DefaultValue = defaultValueAttrib.Value;
}
else
{
_reflector.DefaultValueIsNotPresent = true;
}
}
}
// We call this method a lot. Keep it really small, to make sure it inlines.
private void EnsureReflector()
{
if (_reflector == null)
{
CreateReflector();
}
}
private bool GetFlag(BoolMemberBits flagBit)
{
EnsureReflector();
bool? result = _reflector.GetFlag(flagBit);
if (!result.HasValue)
{
result = LookupBooleanValue(flagBit);
_reflector.SetFlag(flagBit, result.Value);
}
return result.Value;
}
private bool LookupBooleanValue(BoolMemberBits flag)
{
bool result;
switch (flag)
{
case BoolMemberBits.Ambient:
result = LookupIsAmbient();
break;
case BoolMemberBits.Event:
result = LookupIsEvent();
break;
case BoolMemberBits.ReadOnly:
result = LookupIsReadOnly();
break;
case BoolMemberBits.ReadPublic:
result = LookupIsReadPublic();
break;
case BoolMemberBits.WriteOnly:
result = LookupIsWriteOnly();
break;
case BoolMemberBits.WritePublic:
result = LookupIsWritePublic();
break;
default:
Debug.Fail("Enum out of range");
result = GetDefaultFlag(flag);
break;
}
return result;
}
private string LookupConstructorArgument()
{
string result = null;
if (AreAttributesAvailable)
{
result = _reflector.GetAttributeString(typeof(ConstructorArgumentAttribute), out _);
}
return result;
}
private Type LookupSystemType()
{
MemberInfo underlyingMember = UnderlyingMember;
PropertyInfo pi = underlyingMember as PropertyInfo;
if (pi != null)
{
return pi.PropertyType;
}
EventInfo ei = underlyingMember as EventInfo;
if (ei != null)
{
return ei.EventHandlerType;
}
MethodInfo mi = underlyingMember as MethodInfo;
if (mi != null)
{
if (mi.ReturnType != null && mi.ReturnType != typeof(void))
{
return mi.ReturnType;
}
ParameterInfo[] parameters = mi.GetParameters();
if (parameters.Length == 2)
{
return parameters[1].ParameterType;
}
}
return null;
}
#region IEquatable<XamlMember> Members
public override bool Equals(object obj)
{
XamlMember member = obj as XamlMember;
return this == member;
}
public override int GetHashCode()
{
Debug.Assert(DeclaringType != null, "XamlDirective should not call into base.GetHashCode");
return (Name == null ? 0 : Name.GetHashCode()) ^ (int)_memberType ^ DeclaringType.GetHashCode();
}
public bool Equals(XamlMember other)
{
return this == other;
}
public static bool operator ==(XamlMember xamlMember1, XamlMember xamlMember2)
{
if (ReferenceEquals(xamlMember1, xamlMember2))
{
return true;
}
if (xamlMember1 is null || xamlMember2 is null)
{
return false;
}
if (xamlMember1._memberType != xamlMember2._memberType || xamlMember1.Name != xamlMember2.Name)
{
return false;
}
if (xamlMember1.IsDirective)
{
Debug.Assert(xamlMember2.IsDirective);
// DeclaringType is null for directives, so we need to compare namespaces.
// Known and unknown directives are equal if the names and namespaces match
return XamlDirective.NamespacesAreEqual((XamlDirective)xamlMember1, (XamlDirective)xamlMember2);
}
else
{
// Known and unknown members are not equal, even if they otherwise match
return xamlMember1.DeclaringType == xamlMember2.DeclaringType &&
xamlMember1.IsUnknown == xamlMember2.IsUnknown;
}
}
public static bool operator !=(XamlMember xamlMember1, XamlMember xamlMember2)
{
return !(xamlMember1 == xamlMember2);
}
#endregion
enum MemberType : byte
{
Instance,
Attachable,
Directive
}
}
}
|