diff --git a/aspnetcore-features/CustomAttributes/CustomAttributes/CustomAttributeClasses.cs b/aspnetcore-features/CustomAttributes/CustomAttributes/CustomAttributeClasses.cs index 2adea39655..351a4bf50a 100644 --- a/aspnetcore-features/CustomAttributes/CustomAttributes/CustomAttributeClasses.cs +++ b/aspnetcore-features/CustomAttributes/CustomAttributes/CustomAttributeClasses.cs @@ -1,74 +1,87 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; - -namespace CustomAttributes +using System.Reflection; + +namespace CustomAttributes; + +public static class CustomAttributeHelper { - public static class CustomAttributeHelper + private static void WriteOnTheConsole(Attribute attributeInstance) { - private static void WriteOnTheConsole(Attribute attributeInstance) - { - var pInfoList = attributeInstance.GetType().GetProperties(BindingFlags.Public | - BindingFlags.Instance | - BindingFlags.DeclaredOnly); + var pInfoList = attributeInstance.GetType().GetProperties(BindingFlags.Public | + BindingFlags.Instance | + BindingFlags.DeclaredOnly); - Console.WriteLine($"\nThe {attributeInstance} attribute:"); + Console.WriteLine($"\nThe {attributeInstance} attribute:"); - foreach (var pInfo in pInfoList) - Console.WriteLine($"The {pInfo.Name} property is: {pInfo.GetValue(attributeInstance)}"); - } + foreach (var pInfo in pInfoList) + Console.WriteLine($"The {pInfo.Name} property is: {pInfo.GetValue(attributeInstance)}"); + } - public static string? GetAttribute(Type desiredType, Type desiredAttribute) - { - var attributeInstance = Attribute.GetCustomAttribute(desiredType, desiredAttribute); + public static string? GetAttribute(Type desiredType, Type desiredAttribute) + { + var attributeInstance = Attribute.GetCustomAttribute(desiredType, desiredAttribute); - if (attributeInstance == null) - Console.WriteLine($"The class {desiredType} does not have atributes."); - else - WriteOnTheConsole(attributeInstance); + if (attributeInstance == null) + Console.WriteLine($"The class {desiredType} does not have attributes."); + else + WriteOnTheConsole(attributeInstance); - return attributeInstance?.ToString(); - } + return attributeInstance?.ToString(); + } + + public static T? GetAttributeGeneric(Type desiredType) where T : Attribute + { + return desiredType.GetCustomAttribute(); + } + + public static bool HasAttribute(Type desiredType) where T : Attribute + { + return desiredType.IsDefined(typeof(T)); + } - public static List GetAttributesOfMethods(Type elementType) + public static List GetAttributesOfMethods(Type elementType) + { + var attributes = new List(); + + var methodInfoList = elementType.GetMethods(BindingFlags.Public | + BindingFlags.Instance | + BindingFlags.DeclaredOnly); + + if (methodInfoList.Length == 0) { - List attributes = new List(); + Console.WriteLine($"The type {elementType} does not have any methods."); + return attributes; + } - var methodInfoList = elementType.GetMethods(BindingFlags.Public | - BindingFlags.Instance | - BindingFlags.DeclaredOnly); + foreach (var methodInfo in methodInfoList) + { + var attributeList = Attribute.GetCustomAttributes(methodInfo, true); - if (methodInfoList == null || methodInfoList.Length == 0) + if (attributeList.Length == 0) { - Console.WriteLine($"The type {elementType} does not have any methods."); - return attributes; + Console.WriteLine($"The {elementType.Name}.{methodInfo.Name} method does not have attributes."); + continue; } - foreach (var methodInfo in methodInfoList) - { - var attributeList = Attribute.GetCustomAttributes(methodInfo, true); + Console.WriteLine($"The {elementType.Name}.{methodInfo.Name} method's attribute:"); - if (attributeList.Length == 0) - { - Console.WriteLine($"The {elementType.Name}.{methodInfo.Name} method does not have attributes."); - continue; - } + foreach (var att in attributeList) + { + WriteOnTheConsole(att); + attributes.Add(methodInfo.Name + "-" + att.ToString()); + } - Console.WriteLine($"The {elementType.Name}.{methodInfo.Name} method's attribute:"); + Console.WriteLine(); + } - foreach (var att in attributeList) - { - WriteOnTheConsole(att); - attributes.Add(methodInfo.Name + "-" + att.ToString()); - } + return attributes; + } - Console.WriteLine(); - } + public static (int FromAttributeClass, int FromMember) CountInheritedAttributes(MemberInfo member) + where T : Attribute + { + var fromAttributeClass = Attribute.GetCustomAttributes(member, true).OfType().Count(); + var fromMember = member.GetCustomAttributes(true).OfType().Count(); - return attributes; - } + return (fromAttributeClass, fromMember); } } diff --git a/aspnetcore-features/CustomAttributes/CustomAttributes/CustomAttributes.csproj b/aspnetcore-features/CustomAttributes/CustomAttributes/CustomAttributes.csproj index 9ad2a07d38..ed9781c223 100644 --- a/aspnetcore-features/CustomAttributes/CustomAttributes/CustomAttributes.csproj +++ b/aspnetcore-features/CustomAttributes/CustomAttributes/CustomAttributes.csproj @@ -2,7 +2,7 @@ Exe - net6.0 + net10.0 enable enable diff --git a/aspnetcore-features/CustomAttributes/CustomAttributes/DeveloperTaskAttribute.cs b/aspnetcore-features/CustomAttributes/CustomAttributes/DeveloperTaskAttribute.cs index 0836c829f8..56c47e8edd 100644 --- a/aspnetcore-features/CustomAttributes/CustomAttributes/DeveloperTaskAttribute.cs +++ b/aspnetcore-features/CustomAttributes/CustomAttributes/DeveloperTaskAttribute.cs @@ -1,20 +1,13 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace CustomAttributes; -namespace CustomAttributes +[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] +public class DeveloperTaskAttribute : Attribute { - [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] - public class DeveloperTaskAttribute : Attribute + public DeveloperTaskAttribute(Priorities priority) { - public DeveloperTaskAttribute(Priorities priority) - { - Priority = priority; - } - - public Priorities Priority { get; set; } - public string? Description { get; set; } + Priority = priority; } + + public Priorities Priority { get; set; } + public string? Description { get; set; } } diff --git a/aspnetcore-features/CustomAttributes/CustomAttributes/Enums.cs b/aspnetcore-features/CustomAttributes/CustomAttributes/Enums.cs index 3b4e53704c..71e7fe53c3 100644 --- a/aspnetcore-features/CustomAttributes/CustomAttributes/Enums.cs +++ b/aspnetcore-features/CustomAttributes/CustomAttributes/Enums.cs @@ -1,15 +1,8 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace CustomAttributes; -namespace CustomAttributes +public enum Priorities { - public enum Priorities - { - High, - Mid, - Low - } + High, + Mid, + Low } diff --git a/aspnetcore-features/CustomAttributes/CustomAttributes/ManagerTaskAttribute.cs b/aspnetcore-features/CustomAttributes/CustomAttributes/ManagerTaskAttribute.cs index 8f49d8a4e1..122263934d 100644 --- a/aspnetcore-features/CustomAttributes/CustomAttributes/ManagerTaskAttribute.cs +++ b/aspnetcore-features/CustomAttributes/CustomAttributes/ManagerTaskAttribute.cs @@ -1,15 +1,8 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace CustomAttributes; -namespace CustomAttributes +[AttributeUsage(AttributeTargets.Method, Inherited = false)] +public class ManagerTaskAttribute : Attribute { - [AttributeUsage(AttributeTargets.Method, Inherited = false)] - public class ManagerTaskAttribute : Attribute - { - public Priorities Priority { get; set; } - public bool NeedsReport { get; set; } - } + public Priorities Priority { get; set; } + public bool NeedsReport { get; set; } } diff --git a/aspnetcore-features/CustomAttributes/CustomAttributes/MyTasks.cs b/aspnetcore-features/CustomAttributes/CustomAttributes/MyTasks.cs index 5c7d4a9bc0..68fd467eed 100644 --- a/aspnetcore-features/CustomAttributes/CustomAttributes/MyTasks.cs +++ b/aspnetcore-features/CustomAttributes/CustomAttributes/MyTasks.cs @@ -1,27 +1,20 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace CustomAttributes; -namespace CustomAttributes +[TaskDescriptor(Name = "The task's name", + Description = "Some descriptions for the task", + NeedsManager = true, + DeveloperCount = 5)] +public class MyTasks { - [TaskDescriptor(Name = "The task's name", - Description = "Some descriptions for the task", - NeedsManager = true, - DeveloperCount = 5)] - public class MyTasks + [DeveloperTask(Priorities.Low)] + [DeveloperTask(Priorities.High, Description = "High level description")] + public void ScheduleMeeting() { - [DeveloperTask(Priorities.Low)] - [DeveloperTask(Priorities.High, Description = "High level description")] - public void ScheduleMeeting() - { - } + } - [ManagerTask(Priority = Priorities.Mid, NeedsReport = true)] - [DeveloperTask(Priorities.High, Description = "High level description")] - public virtual void ScheduleInterview() - { - } + [ManagerTask(Priority = Priorities.Mid, NeedsReport = true)] + [DeveloperTask(Priorities.High, Description = "High level description")] + public virtual void ScheduleInterview() + { } } diff --git a/aspnetcore-features/CustomAttributes/CustomAttributes/ReviewedAttribute.cs b/aspnetcore-features/CustomAttributes/CustomAttributes/ReviewedAttribute.cs new file mode 100644 index 0000000000..f1ca827e90 --- /dev/null +++ b/aspnetcore-features/CustomAttributes/CustomAttributes/ReviewedAttribute.cs @@ -0,0 +1,6 @@ +namespace CustomAttributes; + +[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property)] +public class ReviewedAttribute : Attribute +{ +} diff --git a/aspnetcore-features/CustomAttributes/CustomAttributes/TaskBoard.cs b/aspnetcore-features/CustomAttributes/CustomAttributes/TaskBoard.cs new file mode 100644 index 0000000000..c04eee6367 --- /dev/null +++ b/aspnetcore-features/CustomAttributes/CustomAttributes/TaskBoard.cs @@ -0,0 +1,12 @@ +namespace CustomAttributes; + +public class TaskBoard +{ + [Reviewed] + public virtual int OpenTasks { get; set; } + + [Reviewed] + public virtual void Archive() + { + } +} diff --git a/aspnetcore-features/CustomAttributes/CustomAttributes/TaskDescriptorAttribute.cs b/aspnetcore-features/CustomAttributes/CustomAttributes/TaskDescriptorAttribute.cs index c8842bcae9..36c2f2e813 100644 --- a/aspnetcore-features/CustomAttributes/CustomAttributes/TaskDescriptorAttribute.cs +++ b/aspnetcore-features/CustomAttributes/CustomAttributes/TaskDescriptorAttribute.cs @@ -1,17 +1,10 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace CustomAttributes; -namespace CustomAttributes +[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)] +public class TaskDescriptorAttribute : Attribute { - [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)] - public class TaskDescriptorAttribute : Attribute - { - public string? Name { get; set; } - public string? Description { get; set; } - public bool NeedsManager { get; set; } - public int DeveloperCount { get; set; } - } + public string? Name { get; set; } + public string? Description { get; set; } + public bool NeedsManager { get; set; } + public int DeveloperCount { get; set; } } diff --git a/aspnetcore-features/CustomAttributes/CustomAttributes/TeamTaskBoard.cs b/aspnetcore-features/CustomAttributes/CustomAttributes/TeamTaskBoard.cs new file mode 100644 index 0000000000..2520dfbf86 --- /dev/null +++ b/aspnetcore-features/CustomAttributes/CustomAttributes/TeamTaskBoard.cs @@ -0,0 +1,10 @@ +namespace CustomAttributes; + +public class TeamTaskBoard : TaskBoard +{ + public override int OpenTasks { get; set; } + + public override void Archive() + { + } +} diff --git a/aspnetcore-features/CustomAttributes/CustomAttributes/YourTasks.cs b/aspnetcore-features/CustomAttributes/CustomAttributes/YourTasks.cs index cd087945a9..2e17c3a356 100644 --- a/aspnetcore-features/CustomAttributes/CustomAttributes/YourTasks.cs +++ b/aspnetcore-features/CustomAttributes/CustomAttributes/YourTasks.cs @@ -1,16 +1,9 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace CustomAttributes; -namespace CustomAttributes +public class YourTasks : MyTasks { - public class YourTasks : MyTasks + [DeveloperTask(Priorities.Mid, Description = "Mid level description")] + public override void ScheduleInterview() { - [DeveloperTask(Priorities.Mid, Description = "Mid level description")] - public override void ScheduleInterview() - { - } } } diff --git a/aspnetcore-features/CustomAttributes/TestProject/PrintAttributesUnitTest.cs b/aspnetcore-features/CustomAttributes/TestProject/PrintAttributesUnitTest.cs index b9d507ccb5..5134981609 100644 --- a/aspnetcore-features/CustomAttributes/TestProject/PrintAttributesUnitTest.cs +++ b/aspnetcore-features/CustomAttributes/TestProject/PrintAttributesUnitTest.cs @@ -35,5 +35,37 @@ public void WhenCorrectYourTaskInput_ThenCorrectMultipleAttOutput() Assert.IsTrue(result); } + + [TestMethod] + public void WhenGenericGetCustomAttribute_ThenTypedInstanceWithoutCast() + { + var descriptor = CustomAttributeHelper.GetAttributeGeneric(typeof(MyTasks)); + var missing = CustomAttributeHelper.GetAttributeGeneric(typeof(MyTasks)); + + Assert.IsNotNull(descriptor); + Assert.AreEqual("The task's name", descriptor.Name); + Assert.AreEqual(5, descriptor.DeveloperCount); + Assert.IsNull(missing); + } + + [TestMethod] + public void WhenIsDefined_ThenTrueOnlyWhereTheAttributeIsApplied() + { + Assert.IsTrue(CustomAttributeHelper.HasAttribute(typeof(MyTasks))); + Assert.IsFalse(CustomAttributeHelper.HasAttribute(typeof(MyTasks))); + } + + [TestMethod] + public void WhenInheritIsTrue_ThenMemberGetCustomAttributesIgnoresItOnPropertiesOnly() + { + var property = typeof(TeamTaskBoard).GetProperty(nameof(TeamTaskBoard.OpenTasks))!; + var method = typeof(TeamTaskBoard).GetMethod(nameof(TeamTaskBoard.Archive))!; + + var onProperty = CustomAttributeHelper.CountInheritedAttributes(property); + var onMethod = CustomAttributeHelper.CountInheritedAttributes(method); + + Assert.AreEqual((1, 0), onProperty); + Assert.AreEqual((1, 1), onMethod); + } } } \ No newline at end of file diff --git a/aspnetcore-features/CustomAttributes/TestProject/TestProject.csproj b/aspnetcore-features/CustomAttributes/TestProject/TestProject.csproj index a9ecf2ff40..a66bc938ee 100644 --- a/aspnetcore-features/CustomAttributes/TestProject/TestProject.csproj +++ b/aspnetcore-features/CustomAttributes/TestProject/TestProject.csproj @@ -1,17 +1,17 @@ - net6.0 + net10.0 enable false - - - - + + + +