了解c#中的属性

时间:2018-03-30 12:45:32

标签: c# attributes

我在研究attributes

时遇到了这段代码
using System;
public class HelpAttribute : Attribute
{
    public HelpAttribute(String Descrition_in)
    {
        this.description = Description_in;
    }
    protected String description;
    public String Description 
    {
        get 
        {
            return this.description;

        }            
    }    
}
[Help("this is a do-nothing class")]
public class AnyClass
{
}

我怀疑的是,当使用this关键字时。 我们知道,this指的是当前对象。 我在这里看不到任何对象?

constructor如何在这里真正起作用?

2 个答案:

答案 0 :(得分:4)

  

我在这里看不到任何对象?

嗯,有。当您使用反射从AnyClass请求属性时,它会使用指定的参数创建属性的新实例。

实际上,该属性将像任何其他类一样创建,只是语法与指定属性不同。

请注意,不会在AnyClass

的构造函数上自动调用该属性
Type t = typeof(AnyClass);
HelpAttribute[] attributes = t.GetCustomAttributes(typeof(HelpAttribute), true)
                              .Cast<HelpAttribute>()
                              .ToArray(); // on this line the attribute is instantiated

Console.WriteLine(attributes.FirstOrDefault()?.Description);

答案 1 :(得分:2)

我喜欢已经给出的答案,只想在那里多加一点;不要将此标记为答案,只需在需要时将其用作帮助者。

该属性不会成为课程的一部分,它只是与课程联系在一起。换句话说,使用AnyClass的任何人都不会关心或了解HelpAttribute,除非他们特别想要/需要知道;当他们这样做时,他们会使用像帕特里克的答案中列出的代码来获取这些信息。

常见的问题是为什么要使用它们以及如何正确使用它们。只需记住属性并非真正修改属性的任何现有对象,而是用于编译和其他关心使用属性的对象。我要发一个例子。

注意:此示例仅用于教育目的。

在此示例通知中,有两种方法可以调用worker。第一个运行工作人员而不关心属性,第二个按自定义PriorityAttribute命令工作人员。另外,我道歉这是一个文件,这不是理想的。我只是这样做,以便在这里发布更容易。但是,您可以将其复制并粘贴到控制台应用程序中,它应该运行得很好。如果重要的话,我使用的是VS2017,.NET 4.7.1和C#7.2。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using static System.Console;
namespace ConsoleApp1
{
    class Program
    {
        public const int MaxNumberOfTasks = 10;
        private static readonly Random Random = new Random();

        static void Main(string[] args)
        {
            var workers = new List<IWorker>(MaxNumberOfTasks);

            for (var i = 0; i < MaxNumberOfTasks; i++)
                workers.Add(GetRandomWorker());

            WriteLine("Random Priority Workers\n");
            RunWorkersAsync(workers).Wait();

            WriteLine("\nSet Priority Workers\n");
            RunWorkersByPriorityAsync(workers).Wait();

            WriteLine("\nWork Complete\n");
            Read();
        }

        private static async Task RunWorkersAsync(List<IWorker> workers)
        {
            foreach (var worker in workers)
                await worker.DoWork();
        }

        private static async Task RunWorkersByPriorityAsync(List<IWorker> workers)
        {
            var highWorkers = new List<IWorker>();
            var mediumWorkers = new List<IWorker>();
            var lowWorkers = new List<IWorker>();

            foreach (var worker in workers)
            {
                var priorityAttribute = (PriorityAttribute)worker.GetType().GetCustomAttributes(typeof(PriorityAttribute), false).FirstOrDefault();
                if (priorityAttribute != null)
                {
                    switch (priorityAttribute.Priority)
                    {
                        case Priority.High:
                            highWorkers.Add(worker);
                            break;
                        case Priority.Medium:
                            mediumWorkers.Add(worker);
                            break;
                        case Priority.Low:
                        default:
                            lowWorkers.Add(worker);
                            break;
                    }
                }
                else
                {
                    lowWorkers.Add(worker);
                }
            }

            await RunWorkersAsync(highWorkers);
            await RunWorkersAsync(mediumWorkers);
            await RunWorkersAsync(lowWorkers);
        }

        private static IWorker GetRandomWorker()
        {
            var randomNumber = Random.Next(0, 3);
            switch (randomNumber)
            {
                case 0:
                    return new HighLevelWorker();
                case 1:
                    return new MediumLevelWorker();
                case 2:
                default:
                    return new LowLevelWorker();
            }
        }
    }

    public interface IWorker
    {
        Task DoWork();
    }

    [AttributeUsage(AttributeTargets.Class)]
    public class PriorityAttribute : Attribute
    {
        public PriorityAttribute(Priority priority) => Priority = priority;
        public Priority Priority { get; }
    }

    public enum Priority
    {
        Low,
        Medium,
        High
    }

    [Priority(Priority.High)]
    public class HighLevelWorker : IWorker
    {
        public async Task DoWork()
        {
            await Task.Delay(200);
            WriteLine($"{nameof(HighLevelWorker)} complete.");
        }
    }

    [Priority(Priority.Medium)]
    public class MediumLevelWorker : IWorker
    {
        public async Task DoWork()
        {
            await Task.Delay(200);
            WriteLine($"{nameof(MediumLevelWorker)} complete.");
        }
    }

    [Priority(Priority.Low)]
    public class LowLevelWorker : IWorker
    {
        public async Task DoWork()
        {
            await Task.Delay(200);
            WriteLine($"{nameof(LowLevelWorker)} complete.");
        }
    }
}

所以有控制台应用程序,这是输出:

Random Priority Workers

MediumLevelWorker complete.
MediumLevelWorker complete.
HighLevelWorker complete.
LowLevelWorker complete.
HighLevelWorker complete.
LowLevelWorker complete.
MediumLevelWorker complete.
MediumLevelWorker complete.
HighLevelWorker complete.
MediumLevelWorker complete.

Set Priority Workers

HighLevelWorker complete.
HighLevelWorker complete.
HighLevelWorker complete.
MediumLevelWorker complete.
MediumLevelWorker complete.
MediumLevelWorker complete.
MediumLevelWorker complete.
MediumLevelWorker complete.
LowLevelWorker complete.
LowLevelWorker complete.

Work Complete

可以从中获取的东西。所有的工人对象完全一样;它们的名称不同,但它们在代码中是相同的,并实现相同的接口;唯一的区别是PriorityAttribute适用于每个。您可以删除该属性,RunWorkersAsyncRunWorkerByPriorityAsync任务都会执行相同的操作。此外,如果您更改任何属性的优先级,您将注意到它,无论该类的名称如何。换句话说,我们可以在有或没有优先级的情况下运行,也可以在需要时修改优先级(尽管在这个例子中,通过命名修改是没有意义的;但这仅仅是出于教育目的。)