如何在 C# 中创建自定义属性

Posted

技术标签:

【中文标题】如何在 C# 中创建自定义属性【英文标题】:How to create a custom attribute in C# 【发布时间】:2011-06-20 06:06:05 【问题描述】:

谁能向我解释一个带有代码的自定义属性的非常基本的示例?

【问题讨论】:

【参考方案1】:

您首先编写一个派生自Attribute 的类:

public class MyCustomAttribute: Attribute

    public string SomeProperty  get; set; 

然后你可以用这个属性装饰任何东西(类、方法、属性……):

[MyCustomAttribute(SomeProperty = "foo bar")]
public class Foo



最后你会使用反射来获取它:

var customAttributes = (MyCustomAttribute[])typeof(Foo).GetCustomAttributes(typeof(MyCustomAttribute), true);
if (customAttributes.Length > 0)

    var myAttribute = customAttributes[0];
    string value = myAttribute.SomeProperty;
    // TODO: Do something with the value

您可以使用AttributeUsage 属性限制可以应用此自定义属性的目标类型:

/// <summary>
/// This attribute can only be applied to classes
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public class MyCustomAttribute : Attribute

关于属性的重要知识:

属性是元数据。 它们在编译时 被烘焙到程序集中,这对您如何设置它们的属性具有非常严重的影响。只接受常量(在编译时已知)值 了解和使用自定义属性的唯一方法是使用Reflection。因此,如果您在运行时不使用反射来获取它们并使用自定义属性装饰某些东西,则不要期望发生太多事情。 属性的创建时间是不确定的。它们由 CLR 实例化,您完全无法控制它。

【讨论】:

我应该在哪个函数/类中`使用反射来获取它` @Hasan A Yousef ,例如在 Entity Framework 中有一个“Key”属性对框架说:这个属性应该被认为是主键。在创建 ORM 时,属性非常有帮助 如何访问属性而不是类的自定义属性? docs.microsoft.com/en-us/dotnet/standard/attributes/… 只是为了完整,这个msdn页面总结的很好 使用泛型,获取类型要容易得多:var value = typeof(Foo).GetCustomAttributes&lt;MyCustomAttribute&gt;().First().SomeProperty;【参考方案2】:

虽然创建自定义Attribute 的代码相当简单,但了解什么是属性非常重要:

属性是编译到程序中的元数据。属性本身不会向类、属性或模块添加任何功能——只是数据。但是,使用反射,可以利用这些属性来创建功能。

因此,例如,让我们看一下来自 Microsoft 的 Enterprise Library 的 Validation Application Block。如果你看一个代码示例,你会看到:

    /// <summary>
    /// blah blah code.
    /// </summary>
    [DataMember]
    [StringLengthValidator(8, RangeBoundaryType.Inclusive, 8, RangeBoundaryType.Inclusive, MessageTemplate = "\"1\" must always have \"4\" characters.")]
    public string Code  get; set; 

从上面的 sn-p 中,人们可能会猜测代码将始终根据验证器的规则进行验证,无论何时更改(在示例中,至少有 8 个字符,最多有 8 个字符)。但事实是,属性什么也没做。如前所述,它仅向属性添加元数据。

然而,企业库有一个Validation.Validate 方法可以查看您的对象,并且对于每个属性,它会检查内容是否违反了属性通知的规则。

所以,这就是您应该如何考虑属性 - 一种将数据添加到代码中的方法,这些数据可能稍后会被其他方法/类/等使用。

【讨论】:

我真的会喜欢这个答案吗?特别是“,还有一个问题,我可以在上述代码的 set 语句中放置相同的条件,以便它与属性有何不同, @slash:你能改写一下吗?我不太明白这个问题。 我认为斜线的意思是询问使用属性和将实际验证代码放入属性设置器之间的区别。答:虽然可以在 setter 中编写代码来验证值,但单独使用属性不会执行验证。属性只是“元数据”。其他地方的另一个代码应该对您使用的属性感兴趣,阅读它们,并根据它们执行操作。一个典型的例子是验证库,正如@BrunoBrant 提到的那样。 不确定为什么这是公认的答案。实际问题(在 Google 中也有索引)是“如何在 C# 中创建 自定义属性”。答案根本没有深入研究该主题。另一方面,第二个答案确实如此。 我认为第二个答案与问题更相关。【参考方案3】:

利用/复制Darin Dimitrov's great response,这是访问属性而不是类的自定义属性的方法:

被装饰的属性[Foo]:

[MyCustomAttribute(SomeProperty = "This is a custom property")]
public string MyProperty  get; set; 

获取它:

PropertyInfo propertyInfo = typeof(Foo).GetProperty(propertyToCheck);
object[] attribute = propertyInfo.GetCustomAttributes(typeof(MyCustomAttribute), true);
if (attribute.Length > 0)

    MyCustomAttribute myAttribute = (MyCustomAttribute)attribute[0];
    string propertyValue = myAttribute.SomeProperty;

您可以将其放入循环中并使用反射来访问类Fooeach 属性上的此自定义属性,以及:

foreach (PropertyInfo propertyInfo in Foo.GetType().GetProperties())

    string propertyName = propertyInfo.Name;

    object[] attribute = propertyInfo.GetCustomAttributes(typeof(MyCustomAttribute), true);
    // Just in case you have a property without this annotation
    if (attribute.Length > 0)
    
        MyCustomAttribute myAttribute = (MyCustomAttribute)attribute[0];
        string propertyValue = myAttribute.SomeProperty;
        // TODO: whatever you need with this propertyValue
    

非常感谢你,达林!!

【讨论】:

如果我们不知道属性上存在哪些类型的属性,我们将如何扩展它? object[] attribute = propertyInfo.GetCustomAttributes(typeof(???), true);我只想遍历所有这些并调用每个未知属性的方法m1() 好问题!这正是为什么抽象和接口是一回事。在这种情况下,您可以分配一个定义了方法 m1() 的接口。这将通知编译器这些类型符合 m1() 合约,并且可以调用此方法。【参考方案4】:

简短的回答是在 c# 中创建一个属性,你只需要从 Attribute 类继承它,就这个:)

但是这里我要详细解释一下属性:

基本上,属性是类,我们可以使用它们将我们的逻辑应用于程序集、类、方法、属性、字段……

在 .Net 中,Microsoft 提供了一些预定义的属性,例如 Obsolete 或 Validation Attributes,例如 ([Required], [StringLength(100)], [Range(0, 999.99)]),我们还有一些属性,例如 ActionFilters asp.net 对于将我们想要的逻辑应用到我们的代码非常有用(如果您有兴趣学习它,请阅读this关于动作过滤器的文章)

另外一点,您可以通过 AttibuteUsage 对您的属性应用一种配置。

  [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = true)]

当你用 AttributeUsage 装饰一个属性类时,你可以告诉 c# 编译器我将在哪里使用这个属性:我将在类、属性的程序集或......上使用它,我的属性是是否允许在定义的目标(类、程序集、属性...)上使用多次?!

在关于属性的定义之后,我将向您展示一个示例: 想象一下,我们想在大学里定义一门新课,我们想让我们大学里的管理员和硕士来定义一门新课,好吗?

namespace ConsoleApp1

    /// <summary>
    /// All Roles in our scenario
    /// </summary>
    public enum UniversityRoles
    
        Admin,
        Master,
        Employee,
        Student
    

    /// <summary>
    /// This attribute will check the Max Length of Properties/fields
    /// </summary>
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = true)]
    public class ValidRoleForAccess : Attribute
    
        public ValidRoleForAccess(UniversityRoles role)
        
            Role = role;
        
        public UniversityRoles Role  get; private set; 

    


    /// <summary>
    /// we suppose that just admins and masters can define new Lesson
    /// </summary>
    [ValidRoleForAccess(UniversityRoles.Admin)]
    [ValidRoleForAccess(UniversityRoles.Master)]
    public class Lesson
    
        public Lesson(int id, string name, DateTime startTime, User owner)
        
            var lessType = typeof(Lesson);
            var validRolesForAccesses = lessType.GetCustomAttributes<ValidRoleForAccess>();

            if (validRolesForAccesses.All(x => x.Role.ToString() != owner.GetType().Name))
            
                throw new Exception("You are not Allowed to define a new lesson");
            
            
            Id = id;
            Name = name;
            StartTime = startTime;
            Owner = owner;
        
        public int Id  get; private set; 
        public string Name  get; private set; 
        public DateTime StartTime  get; private set; 

        /// <summary>
        /// Owner is some one who define the lesson in university website
        /// </summary>
        public User Owner  get; private set; 

    

    public abstract class User
    
        public int Id  get; set; 
        public string Name  get; set; 
        public DateTime DateOfBirth  get; set; 
    


    public class Master : User
    
        public DateTime HireDate  get; set; 
        public Decimal Salary  get; set; 
        public string Department  get; set; 
    

    public class Student : User
    
        public float GPA  get; set; 
    



    class Program
    
        static void Main(string[] args)
        

            #region  exampl1

            var master = new Master()
            
                Name = "Hamid Hasani",
                Id = 1,
                DateOfBirth = new DateTime(1994, 8, 15),
                Department = "Computer Engineering",
                HireDate = new DateTime(2018, 1, 1),
                Salary = 10000
            ;
            var math = new Lesson(1, "Math", DateTime.Today, master);

            #endregion

            #region exampl2
            var student = new Student()
            
                Name = "Hamid Hasani",
                Id = 1,
                DateOfBirth = new DateTime(1994, 8, 15),
                GPA = 16
            ;
            var literature = new Lesson(2, "literature", DateTime.Now.AddDays(7), student);
            #endregion

            ReadLine();
        
    



在现实的编程世界中,我们可能不会使用这种方法来使用属性,我之所以这么说是因为它在使用属性方面具有教育意义

【讨论】:

以上是关于如何在 C# 中创建自定义属性的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法在 Kivy 中创建自定义属性?

如何在 C# 中创建自定义登录 Windows 屏幕?

如何在 QT5.6.1 中创建自定义按钮

如何在 Blend 中创建自定义列表

如何使用 C# 中的 Nuget 包在谷歌分析中创建自定义维度和自定义指标

如何在 selenium c# 中创建自定义显式等待函数,传入 WebElements 而不是 By