C#,特性,属性,索引器

news/2024/7/24 1:04:53 标签: c#, 开发语言

目录

特性

规定特性

预定义特性

1,AttributeUsage

2,Conditional

3,Obsolete

创建自定义特性

1,声明自定义特性

2,构建自定义特性

应用自定义特性

属性

访问器

抽象属性

索引器

语法

索引器的用途

重载索引器


特性

        定义:特性是运行时传递程序中的各种元素(类、方法、结构、枚举、组件)行为信息的声明性标签。可以特过特性向程序添加声明性信息。

        一个声明性标签是通过放置在它所应用的元素前面的方括号([ ])来描述的。特性(Attribute)用于添加元数据,如编译器指令和注释、描述、方法、类等其他信息。.Net 框架提供了两种类型的特性:预定义特性和自定义特性。

规定特性

特性的名称和值是在方括号内规定的,放置在它所应用的元素之前。positional_parameters 规定必需的信息,name_parameter 规定可选的信息。

[attribute(positional_parameters, name_parameter = value, ...)]
element

预定义特性

.NET框架提供了三种预定义特性:

  • AttributeUsage

  • Conditional

  • Obsolete

1,AttributeUsage

AttributeUsage描述了如何使用一个自定义特性类,规定了特性可运用到的项目类型,语法如下:

[AttributeUsage(
   validon,
   AllowMultiple=allowmultiple,
   Inherited=inherited
)]

其中,

参数validon规定特性可被放置的语言元素。它是枚举器 AttributeTargets 的值的组合。默认值是 AttributeTargets.All

参数 allowmultiple(可选的)为该特性的 AllowMultiple 属性(property)提供一个布尔值。如果为 true,则该特性是多用的。默认值是 false(单用的)。

参数 inherited(可选的)为该特性的 Inherited 属性(property)提供一个布尔值。如果为 true,则该特性可被派生类继承。默认值是 false(不被继承)。

2,Conditional

这个预定义特性标记了一个条件方法,其执行依赖于指定的预处理标识符,它会引起方法调用的条件编译,取决于指定的值,比如 DebugTrace。例如,当调试代码时显示变量的值。规定该特性的语法如下:

[Conditional(
   conditionalSymbol
)]

例如:

#define DEBUG
using System;
using System.Diagnostics;
public class Myclass
{
    [Conditional("DEBUG")]
    public static void Message(string msg)
    {
        Console.WriteLine(msg);
    }
}
class Test
{
    static void function1()
    {
        Myclass.Message("In Function 1.");
        function2();
    }
    static void function2()
    {
        Myclass.Message("In Function 2.");
    }
    public static void Main()
    {
        Myclass.Message("In Main function.");
        function1();
        Console.ReadKey();
    }
}

结果:

In Main function.
In Function 1.
In Function 2.

3,Obsolete

标记了不应被使用的程序实体。它可以让您通知编译器丢弃某个特定的目标元素。例如,当一个新方法被用在一个类中,但是您仍然想要保持类中的旧方法,您可以通过显示一个应该使用新方法,而不是旧方法的消息,来把它标记为 obsolete(过时的)。

规定的语法特性如下:

[Obsolete(
   message
)]
[Obsolete(
   message,
   iserror
)]

其中:

参数message,是一个字符串,描述项目为什么过时,以及该用什么替代。

参数iserror,是一个布尔值。如果该值为 true,编译器应把该项目的使用当作一个错误。默认值是 false(编译器生成一个警告)。

实例:

using System;
public class MyClass
{
   [Obsolete("Don't use OldMethod, use NewMethod instead", true)]
   static void OldMethod()
   { 
      Console.WriteLine("It is the old method");
   }
   static void NewMethod()
   { 
      Console.WriteLine("It is the new method"); 
   }
   public static void Main()
   {
      OldMethod();
   }
}

结果:

 Don't use OldMethod, use NewMethod instead

这是一个错误信息说明。

创建自定义特性

.NET框架允许船舰自定义特性,由于存储声明性信息,并且可以在运行时被检索,该信息根据设计标准和应用程序的需要可以与任何目标元素相关。

创建并且使用自定义特性需要四个步骤:

  • 声明自定义特性

  • 构建自定义特性

  • 在目标程序元素上应用自定义特性

  • 特过反射访问特性

最后一个步骤包含编写一个简单的程序来读取元数据以便来查找各种符号。

1,声明自定义特性

一个新的自定义特性应派生自 System.Attribute 类。例如:

// 一个自定义特性 BugFix 被赋给类及其成员
[AttributeUsage(AttributeTargets.Class |
AttributeTargets.Constructor |
AttributeTargets.Field |
AttributeTargets.Method |
AttributeTargets.Property,
AllowMultiple = true)]
​
public class DeBugInfo : System.Attribute

我们声明了一个DeBugInfo的特性

2,构建自定义特性

构建一个名为DeBugInfo的特性,它存储下面的信息:

  • bug的编号代码

  • 开发人员

  • 更新日期

  • 存储开发人员标记的字符串消息

DeBugInfo 类将带有三个用于存储前三个信息的私有属性(property)和一个用于存储消息的公有属性(property)。所以 bug 编号、开发人员和更新日期将是 DeBugInfo 类的必需的定位( positional)参数,消息将是一个可选的命名(named)参数。每个特性必须至少有一个构造函数。必需的定位( positional)参数应通过构造函数传递。下面的代码演示了 DeBugInfo 类:

// 一个自定义特性 BugFix 被赋给类及其成员
[AttributeUsage(AttributeTargets.Class |
AttributeTargets.Constructor |
AttributeTargets.Field |
AttributeTargets.Method |
AttributeTargets.Property,
AllowMultiple = true)]
​
public class DeBugInfo : System.Attribute
{
  private int bugNo;
  private string developer;
  private string lastReview;
  public string message;
​
  public DeBugInfo(int bg, string dev, string d)
  {
      this.bugNo = bg;
      this.developer = dev;
      this.lastReview = d;
  }
​
  public int BugNo
  {
      get
      {
          return bugNo;
      }
  }
  public string Developer
  {
      get
      {
          return developer;
      }
  }
  public string LastReview
  {
      get
      {
          return lastReview;
      }
  }
  public string Message
  {
      get
      {
          return message;
      }
      set
      {
          message = value;
      }
  }
}

应用自定义特性

通过把特性放置在紧接着它的目标之前,来应用该特性:

[DeBugInfo(45, "Zara Ali", "12/8/2012", Message = "Return type mismatch")]
[DeBugInfo(49, "Nuha Ali", "10/10/2012", Message = "Unused variable")]
class Rectangle
{
  // 成员变量
  protected double length;
  protected double width;
  public Rectangle(double l, double w)
  {
      length = l;
      width = w;
  }
  [DeBugInfo(55, "Zara Ali", "19/10/2012",
  Message = "Return type mismatch")]
  public double GetArea()
  {
      return length * width;
  }
  [DeBugInfo(56, "Zara Ali", "19/10/2012")]
  public void Display()
  {
      Console.WriteLine("Length: {0}", length);
      Console.WriteLine("Width: {0}", width);
      Console.WriteLine("Area: {0}", GetArea());
  }
}

属性

属性是类、结构和接口的命名成员。类或结构中的成员变量或者方法称为域。属性是域的扩展,且可以使用相同的语法来访问。他们使用访问器让私有域的值可以被读写或操作。

属性不会确定存储位置,它们具有可读写或计算它们值的访问器。

访问器

属性的访问器包含有助于获取或设置属性的可执行语句。访问器声明可包含一个get访问器,set访问器,或者同时包含,例如:

// 声明类型为 string 的 Code 属性
public string Code
{
   get
   {
      return code;
   }
   set
   {
      code = value;
   }
}
​
// 声明类型为 string 的 Name 属性
public string Name
{
   get
   {
     return name;
   }
   set
   {
     name = value;
   }
}
​
// 声明类型为 int 的 Age 属性
public int Age
{ 
   get
   {
      return age;
   }
   set
   {
      age = value;
   }
}

实例:

using System;
namespace runoob
{
   class Student
   {
​
      private string code = "N.A";
      private string name = "not known";
      private int age = 0;
​
      // 声明类型为 string 的 Code 属性
      public string Code
      {
         get
         {
            return code;
         }
         set
         {
            code = value;
         }
      }
   
      // 声明类型为 string 的 Name 属性
      public string Name
      {
         get
         {
            return name;
         }
         set
         {
            name = value;
         }
      }
​
      // 声明类型为 int 的 Age 属性
      public int Age
      {
         get
         {
            return age;
         }
         set
         {
            age = value;
         }
      }
      public override string ToString()
      {
         return "Code = " + Code +", Name = " + Name + ", Age = " + Age;
      }
    }
    class ExampleDemo
    {
      public static void Main()
      {
         // 创建一个新的 Student 对象
         Student s = new Student();
            
         // 设置 student 的 code、name 和 age
         s.Code = "001";
         s.Name = "Zara";
         s.Age = 9;
         Console.WriteLine("Student Info: {0}", s);
         // 增加年龄
         s.Age += 1;
         Console.WriteLine("Student Info: {0}", s);
         Console.ReadKey();
       }
   }
}

结果:

Student Info: Code = 001, Name = Zara, Age = 9
Student Info: Code = 001, Name = Zara, Age = 10

抽象属性

抽象类可拥有抽象属性,这些属性应在派生类中被实现。下面的程序说明了这点:

using System;
namespace runoob
{
   public abstract class Person
   {
      public abstract string Name
      {
         get;
         set;
      }
      public abstract int Age
      {
         get;
         set;
      }
   }
   class Student : Person
   {
​
      private string code = "N.A";
      private string name = "N.A";
      private int age = 0;
​
      // 声明类型为 string 的 Code 属性
      public string Code
      {
         get
         {
            return code;
         }
         set
         {
            code = value;
         }
      }
   
      // 声明类型为 string 的 Name 属性
      public override string Name
      {
         get
         {
            return name;
         }
         set
         {
            name = value;
         }
      }
​
      // 声明类型为 int 的 Age 属性
      public override int Age
      {
         get
         {
            return age;
         }
         set
         {
            age = value;
         }
      }
      public override string ToString()
      {
         return "Code = " + Code +", Name = " + Name + ", Age = " + Age;
      }
   }
   class ExampleDemo
   {
      public static void Main()
      {
         // 创建一个新的 Student 对象
         Student s = new Student();
            
         // 设置 student 的 code、name 和 age
         s.Code = "001";
         s.Name = "Zara";
         s.Age = 9;
         Console.WriteLine("Student Info:- {0}", s);
         // 增加年龄
         s.Age += 1;
         Console.WriteLine("Student Info:- {0}", s);
         Console.ReadKey();
       }
   }
}

结果:

Student Info: Code = 001, Name = Zara, Age = 9
Student Info: Code = 001, Name = Zara, Age = 10

索引器

索引器允许一个对象可以像数组一样使用下标的方式来进行访问。当为类定义一个索引器的时候,该类的行为就会像是一个虚拟的数组,可以使用数组访问运算符来访问该类的成员。

语法

一维索引器的语法:

element-type this[int index] 
{
   // get 访问器
   get 
   {
      // 返回 index 指定的值
   }
​
   // set 访问器
   set 
   {
      // 设置 index 指定的值 
   }
}

索引器的用途

索引器的行为的声明在某种程度上类似于属性,就像属性可以使用get,set访问器来定义索引器。但是属性返回或者设置一个特定的数据成员,而索引器返回或设置对象实例的一个特定值,它把实例数据分为更小的部分,并索引每个部分,获取或设置每个部分。

定义一个属性包括提供属性的名称。索引器定义的时候不带有名称,但是带有关键字this,它指向对象实例,例子:

using System;
namespace IndexerApplication
{
   class IndexedNames
   {
      private string[] namelist = new string[size];
      static public int size = 10;
      public IndexedNames()
      {
         for (int i = 0; i < size; i++)
         namelist[i] = "N. A.";
      }
      public string this[int index]
      {
         get
         {
            string tmp;
​
            if( index >= 0 && index <= size-1 )
            {
               tmp = namelist[index];
            }
            else
            {
               tmp = "";
            }
​
            return ( tmp );
         }
         set
         {
            if( index >= 0 && index <= size-1 )
            {
               namelist[index] = value;
            }
         }
      }
​
      static void Main(string[] args)
      {
         IndexedNames names = new IndexedNames();
         names[0] = "Zara";
         names[1] = "Riz";
         names[2] = "Nuha";
         names[3] = "Asif";
         names[4] = "Davinder";
         names[5] = "Sunil";
         names[6] = "Rubic";
         for ( int i = 0; i < IndexedNames.size; i++ )
         {
            Console.WriteLine(names[i]);
         }
         Console.ReadKey();
      }
   }
}

结果:

Zara
Riz
Nuha
Asif
Davinder
Sunil
Rubic
N. A.
N. A.
N. A.

重载索引器

索引器可以被重载,索引器声明的时候也可以带有多个参数,并且每个参数可以是不同类型,没必要让索引器必须是整型的,C#也许索引器可以说其他类型,例如字符串类型。

实例:

using System;
namespace IndexerApplication
{
   class IndexedNames
   {
      private string[] namelist = new string[size];
      static public int size = 10;
      public IndexedNames()
      {
         for (int i = 0; i < size; i++)
         {
          namelist[i] = "N. A.";
         }
      }
      public string this[int index]
      {
         get
         {
            string tmp;
​
            if( index >= 0 && index <= size-1 )
            {
               tmp = namelist[index];
            }
            else
            {
               tmp = "";
            }
​
            return ( tmp );
         }
         set
         {
            if( index >= 0 && index <= size-1 )
            {
               namelist[index] = value;
            }
         }
      }
      public int this[string name]
      {
         get
         {
            int index = 0;
            while(index < size)
            {
               if (namelist[index] == name)
               {
                return index;
               }
               index++;
            }
            return index;
         }
​
      }
​
      static void Main(string[] args)
      {
         IndexedNames names = new IndexedNames();
         names[0] = "Zara";
         names[1] = "Riz";
         names[2] = "Nuha";
         names[3] = "Asif";
         names[4] = "Davinder";
         names[5] = "Sunil";
         names[6] = "Rubic";
         // 使用带有 int 参数的第一个索引器
         for (int i = 0; i < IndexedNames.size; i++)
         {
            Console.WriteLine(names[i]);
         }
         // 使用带有 string 参数的第二个索引器
         Console.WriteLine(names["Nuha"]);
         Console.ReadKey();
      }
   }
}

结果:

Zara
Riz
Nuha
Asif
Davinder
Sunil
Rubic
N. A.
N. A.
N. A.
2

http://www.niftyadmin.cn/n/4943335.html

相关文章

C语言实现哈希搜索算法

一、哈希搜索算法原理 哈希搜索&#xff0c;也叫散列查找&#xff0c;是一种通过哈希表&#xff08;散列表&#xff09;实现快速查找目标元素的算法。哈希搜索算法通常适用于需要快速查找一组数据中是否存在某个元素的场景&#xff0c;其时间复杂度最高为 O(1)&#xff0c;而平…

【Linux操作系统】举例解释Linux系统编程中文件io常用的函数

在Linux系统编程中&#xff0c;文件IO操作是非常常见和重要的操作之一。通过文件IO操作&#xff0c;我们可以打开、读取、写入和关闭文件&#xff0c;对文件进行定位、复制、删除和重命名等操作。本篇博客将介绍一些常用的文件IO操作函数。 文章目录 1. open()1.1 原型、参数及…

Linux文件属性查看和修改学习

一、基本属性 1、看懂文件属性&#xff1a; Linux系统是一种典型的多用户系统&#xff0c;不同的用户处于不同的地位&#xff0c;拥有不同的权限。为了保护系统的安全性&#xff0c; Linux系统对不同的用户访问同一文件&#xff08;包括目录文件&#xff09;的权限做了不同的…

vue echarts中按钮点击后修改值 watch数据变化后刷新图表

1 点击按钮 {feature: {myBtn1: {show: true,title: 反转Y轴,showTitle: true,icon: path://M512 0A512 512 0 1 0 512 1024A512 512 0 0 0 512 0M320 320V192h384v128zM128 416V288h256v128zM320 704V576h384v128zM128 800V672h256v128z,onclick: () > {dataSetting.rever…

re学习(33)攻防世界-secret-galaxy-300(动态调试)

下载压缩包&#xff1a; 下载链接&#xff1a;https://adworld.xctf.org.cn/challenges/list 参考文章&#xff1a;攻防世界逆向高手题之secret-galaxy-300_沐一 林的博客-CSDN博客 发现这只是三个同一类型文件的三个不同版本而已&#xff0c;一个windows32位exe&#xff0…

2023年度漏洞预警

1 漏洞 漏洞是硬件&#xff0c;软件&#xff0c;协议的具体实现或系统安全策略上存在的缺陷。从而可以使用攻击者能够在破坏系统。 2 漏洞汇总数据 以下数据针对 23 年截至8月期间爆发的高危严重漏洞进行了数据统计和分析&#xff0c; 具体的数据如下所示&#xff1a; 漏洞…

解释Python脚本程序”__name__”变量及其作用

问题:解释Python脚本程序”__name__”变量及其作用 __name__是Python自身定义的内置变量 每一个模块都拥有自己的__name__变量 如果模块是程序的入口,则__name__变量值为__main__,当__name__等于__main__时,通常表示模块位于最高级代码环境,你可以理解为该模块为程序的入…

【bug】把steamVR的包导入新建的工程后,竟然出现了。。。。两个报错

“有哪些让你目瞪口呆的bug&#xff1f;” &#x1f4a6;对于做游戏来说&#xff0c;真的遇到过很多让我“目瞪口呆”的&#xff0c;比如躺着跑的马&#xff0c;转的停不下来的鸟&#xff0c;卡在墙里的人等等&#xff0c;真的很好笑。 &#x1f494;但是&#xff0c;记录一个最…