[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/r2d2m/ClearScript/master/ClearScript/CustomAttributes.cs [Back]  [Original]

// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.

using System;
using System.Collections.Generic;
using System.Reflection;
using Microsoft.ClearScript.Util;

namespace Microsoft.ClearScript
{
    internal static partial class CustomAttributes
    {
        private static readonly object cacheLock = new object();

        public static T[] GetOrLoad(ICustomAttributeProvider resource, bool inherit) where T : Attribute
        {
            lock (cacheLock)
            {
                return GetOrLoad(cache.GetOrCreateValue(resource), resource, inherit);
            }
        }

        public static bool Has(ICustomAttributeProvider resource, bool inherit) where T : Attribute
        {
            lock (cacheLock)
            {
                return Has(cache.GetOrCreateValue(resource), resource, inherit);
            }
        }

        private static T[] GetOrLoad(CacheEntry entry, ICustomAttributeProvider resource, bool inherit) where T : Attribute
        {
            if (entry.TryGet(out var attrs))
            {
                return attrs;
            }

            attrs = GetOrLoad(GetIsBypass(entry, resource), resource, inherit);
            entry.Add(attrs);

            return attrs;
        }

        private static bool Has(CacheEntry entry, ICustomAttributeProvider resource, bool inherit) where T : Attribute
        {
            return GetOrLoad(entry, resource, inherit).Length > 0;
        }

        private static T[] GetOrLoad(bool isBypass, ICustomAttributeProvider resource, bool inherit) where T : Attribute
        {
            var loader = isBypass ? HostSettings.DefaultCustomAttributeLoader : HostSettings.CustomAttributeLoader;
            return loader.LoadCustomAttributes(resource, inherit) ?? ArrayHelpers.GetEmptyArray();
        }

        private static bool Has(bool isBypass, ICustomAttributeProvider resource, bool inherit) where T : Attribute
        {
            return GetOrLoad(isBypass, resource, inherit).Length > 0;
        }

        private static bool GetIsBypass(ICustomAttributeProvider resource)
        {
            // ReSharper disable once InconsistentlySynchronizedField
            return GetIsBypass(cache.GetOrCreateValue(resource), resource);
        }

        private static bool GetIsBypass(CacheEntry entry, ICustomAttributeProvider resource)
        {
            if (!entry.IsBypass.HasValue)
            {
                entry.IsBypass = GetIsBypassInternal(resource);
            }

            return entry.IsBypass.Value;
        }

        private static bool GetIsBypassInternal(ICustomAttributeProvider resource)
        {
            if (Has(true, resource, false))
            {
                return true;
            }

            var parent = GetParent(resource);
            if (parent != null)
            {
                return GetIsBypass(parent);
            }

            return false;
        }

        private static ICustomAttributeProvider GetParent(ICustomAttributeProvider resource)
        {
            if (resource is ParameterInfo parameter)
            {
                return parameter.Member;
            }

            if (resource is Type type)
            {
                return (type.DeclaringType as ICustomAttributeProvider) ?? type.Module;
            }

            if (resource is MemberInfo member)
            {
                return member.DeclaringType;
            }

            if (resource is Module module)
            {
                return module.Assembly;
            }

            return null;
        }

        #region Nested type: CacheEntry

        // ReSharper disable ClassNeverInstantiated.Local

        private sealed class CacheEntry
        {
            private readonly Dictionary map = new Dictionary();

            public bool? IsBypass { get; set; }

            public void Add(T[] attrs)
            {
                map.Add(typeof(T), attrs);
            }

            public bool TryGet(out T[] attrs)
            {
                if (map.TryGetValue(typeof(T), out var attrsObject))
                {
                    attrs = attrsObject as T[];
                    return true;
                }

                attrs = null;
                return false;
            }
        }

        // ReSharper restore ClassNeverInstantiated.Local

        #endregion
    }

    [AttributeUsage(AttributeTargets.All, Inherited = false)]
    internal sealed class BypassCustomAttributeLoaderAttribute : Attribute
    {
    }
}

Web Proxy Viewer  |  New URL  |  Original Page