Location>code7788 >text

NET Core Attribute (Attribute) underlying the principle of shallow talk

Popularity:669 ℃/2024-11-19 16:41:09

synopsis

image
Without further ado, the rotten information is simply thatComments for the code to see

Attribute usage scenarios

Attributes are not just limited to C#, they provide very large expansion points throughout the .NET Framework, and there are Attributes everywhere!

  1. compiler layer
    For example, Obsolete, Conditional
  2. C# layer
    GET,POST,Max,Range,Require
  3. CLR VM Layer
    StructLayout,DllImport
  4. JIT layer
    MethodImpl

Attribute Calls in C#

As a common example, read custom features on enumerations.

    public enum Test
    {
        [EnumDescription("hhhhhh")]
        None = 0,
        [EnumDescription("xxxxxx")]
        Done =1
    }
	private static IEnumerable<string> GetEnumDescriptions(this Enum e)
	{
		IEnumerable<string> result = null;
        var type = ();
        var fieldInfo = (());
        var attr = fieldInfo?.GetCustomAttributes(typeof(EnumDescriptionAttribute), false);
        if (attr?.Length > 0)
        {
			result = <EnumDescriptionAttribute>().Select(x => );
        }
		return result ?? <string>();
	}

As you can see, the underlying Attribute implementation in C# still relies on reflection, which is why Attributes areComments written to the code, so the optimization ideas for reflection can also be used in Attribute.
For example, in your code, use Dictionary to cache the result set. Avoid performance problems caused by too many calls to reflection.

        private static IEnumerable<string> GetEnumDescriptionsCache(this Enum e)
        {
            var key = $"{().Name}_{()}";
            if (_enumMap.ContainsKey(key))
            {
                return _enumMap[key];
            }
            else
            {
                var result = GetEnumDescriptions(e);
                _enumMap.TryAdd(key, result);
                return result;
            }
        }

The performance difference caused by 100,000 cycles is still noticeable
image

Use of Attrubute

JsonConverter as a blueprint for an example.

    public class Person
    {
        [JsonConverter(typeof(DateTimeConverter))]
        public DateTime CreateTime { get; set; }
    }
	public class DateTimeConverter : JsonConverter<DateTime>
    {
        public override DateTime ReadJson(JsonReader reader, Type objectType, DateTime existingValue, bool hasExistingValue, JsonSerializer serializer)
        {
            if ( == null)
                return ;

            if (((), out DateTime result))
                return result;

            return ;
        }

        public override void WriteJson(JsonWriter writer, DateTime value, JsonSerializer serializer)
        {
            (("yyyy-MM-dd HH:mm:ss"));
        }
    }

Defines an Attribute: JsonConverter. the underlying call is as follows:

        [RequiresUnreferencedCode()]
        [RequiresDynamicCode()]
        public static JsonConverter? GetJsonConverter(object attributeProvider)
        {
			// The bottom layer still calls theReflection,For performance,Object metadata is also cached。
            JsonConverterAttribute? converterAttribute = GetCachedAttribute<JsonConverterAttribute>(attributeProvider);

            if (converterAttribute != null)
            {
                Func<object[]?, object> creator = ();
                if (creator != null)
                {
                    return (JsonConverter)creator();
                }
            }

            return null;
        }

/JamesNK//blob/master/Src//Serialization/

Attribute Calls on the CLR

    public class NativeMethods
    {
        [DllImport("xxxxx", EntryPoint = "add", CallingConvention = )]
        public extern static int ManagedAdd(int a, int b);
    }

In the CLR, the same is used to call C/C++ exported functions. Those interested can use windbg to view the thread call stack. As well as in MetaData there is an ImplMap table that stores the mapping relationship between C# methods and C++ functions

Attribute invocation on JITs

    public class Person
    {
        public int id { get; set; } = 0;

        [MethodImpl()]
        public void SyncMethod()
        {
            id++;
        }
    }

The JIT automatically injects synchronization code for this Attribute
image
image

The essence of this is the injection of lock synchronization block code, just granularity over the entire method. Relatively large

reach a verdict

Attrubute is at the C# level and uses reflection at the bottom. Therefore when using a custom Attribute, use caching as appropriate to improve performance