【从Java到C#系列 三】从java到.net 高级

简介: 【从Java到C#系列 三】从java到.net 高级

上一篇基本比较了下两种语言的差异,其实可以看的出,二者大同小异,但C#提供了一些相比较而言差异有优势的地方,这一篇来进行分析,也是一个学习的过程,由于是初学者,如果理解有不到位的地方,欢迎指出错误,下一篇将介绍C#是最大优势,委托和事件,以及可能用到委托和事件的后续部分:匿名方法,不安全代码,多线程

学习教程来自于http://www.runoob.com/csharp/csharp-attribute.html

#特性

在我看来其实,C#里的特性其实和java里的注解或者在框架里常用的标签很像,就是用一个标签来代替大量的代码。或者更准确的理解就是,我感觉特性很像spring里的AOP(日志系统的应用),不同于OOP,它横向的提炼相同方法,属性,类。

##特性定义

**特性就是在类的类名称、属性、方法等上面加一个标记,使这些类、属性、方法等具有某些统一的特征,从而达到某些特殊的需要。**举个小栗子:方法的异常捕捉,你是否还在某些可能出现异常的地方(例如数据库的操作、文件的操作等)经常使用try…catch。这个时候如果使用特性,就可 以大大减少方法里面的try…catch的使用。你只需要定义一个专门捕捉异常的特性类ExceptionExAttribute,然后给这个特性类 做些特殊处理,比如给它增加一个AOP拦截的功能。那么在可能出现异常的方法名称上 面加上一个[ExceptionEx]特性标签,这个方法就具有自动捕捉异常的能力。由此可见,特性可以减少统一需求的代码量.

##特性规范

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

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

##特性分类

###预定义特性

Net 框架提供了三种预定义特性:AttributeUsage,Conditional,Obsolete

####AttributeUsage

预定义特性 AttributeUsage 描述了如何使用一个自定义特性类。它规定了特性可应用到的项目的类型。

[AttributeUsage(
   validon,
   AllowMultiple=allowmultiple,
   Inherited=inherited
)]
  • 参数 validon 规定特性可被放置的语言元素。它是枚举器 AttributeTargets 的值的组合。默认值是 AttributeTargets.All。
  • 参数 allowmultiple(可选的)为该特性的 AllowMultiple 属性(property)提供一个布尔值。如果为 true,则该特性是多用的。默认值是 false(单用的)。
  • 参数 inherited(可选的)为该特性的 Inherited 属性(property)提供一个布尔值。如果为 true,则该特性可被派生类继承。默认值是 false(不被继承)。
[AttributeUsage(AttributeTargets.Class |
AttributeTargets.Constructor |
AttributeTargets.Field |
AttributeTargets.Method |
AttributeTargets.Property, 
AllowMultiple = true)]

####Conditional

标记一个条件方法,执行依赖于指定的预处理标识符,当程序触发时执行例如我想在调试代码的时候显示,则只需要设置为debug

当调试代码的时候,触发该类,感觉有点儿观察者模式的意思。

####obselete

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

这里当我使用旧方法的时候就会触发错误,当然可以设置为警告

规范写法如下:

[Obsolete(
   message
)]
[Obsolete(
   message,
   iserror
)]
  • 参数 message,是一个字符串,描述项目为什么过时的原因以及该替代使用什么。
  • 参数 iserror,是一个布尔值。如果该值为 true,编译器应把该项目的使用当作一个错误。默认值是 false(编译器生成一个警告)。
    ###自定义特性
    .Net 框架允许创建自定义特性,用于存储声明性的信息,且可在运行时被检索。该信息根据设计标准和应用程序需要,可与任何目标元素相关。
    创建并使用自定义特性包含四个步骤:
  • 声明自定义特性
  • 构建自定义特性
  • 在目标程序元素上应用自定义特性
  • 通过反射访问特性

最后一个步骤包含编写一个简单的程序来读取元数据以便查找各种符号。元数据是用于描述其他数据的数据和信息。该程序应使用反射来在运行时访问特性

举例如下:让我们构建一个名为 DeBugInfo 的自定义特性,该特性将存储调试程序获得的信息。它存储下面的信息:

  • bug 的代码编号
  • 辨认该 bug 的开发人员名字
  • 最后一次审查该代码的日期
  • 一个存储了开发人员标记的字符串消息

我们的 DeBugInfo 类将带有三个用于存储前三个信息的私有属性(property)和一个用于存储消息的公有属性(property)。所以 bug 编号、开发人员名字和审查日期将是 DeBugInfo 类的必需的定位( positional)参数,消息将是一个可选的命名(named)参数。

每个特性必须至少有一个构造函数。必需的定位( positional)参数应通过构造函数传递。

####声明和构建自定义特性

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

// 一个自定义特性 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());
  }
}

####使用反射来读取元数据

class ExecuteRectangle
    {
        static void Main(string[] args)
        {
            Rectangle r = new Rectangle(4.5, 7.5);
            r.Display();
            Type type = typeof(Rectangle);
            // 遍历 Rectangle 类的特性
            foreach (Object attributes in type.GetCustomAttributes(false))
            {
                DeBugInfo dbi = (DeBugInfo)attributes;
                if (null != dbi)
                {
                    Console.WriteLine("Bug no: {0}", dbi.BugNo);
                    Console.WriteLine("Developer: {0}", dbi.Developer);
                    Console.WriteLine("Last Reviewed: {0}",
     dbi.LastReview);
                    Console.WriteLine("Remarks: {0}", dbi.Message);
                }
            }
            // 遍历方法特性
            foreach (MethodInfo m in type.GetMethods())
            {
                foreach (Attribute a in m.GetCustomAttributes(true))
                {
                    DeBugInfo dbi = (DeBugInfo)a;
                    if (null != dbi)
                    {
                        Console.WriteLine("Bug no: {0}, for Method: {1}",
      dbi.BugNo, m.Name);
                        Console.WriteLine("Developer: {0}", dbi.Developer);
                        Console.WriteLine("Last Reviewed: {0}",
      dbi.LastReview);
                        Console.WriteLine("Remarks: {0}", dbi.Message);
                    }
                }
            }
            Console.ReadLine();
        }
    }
}

运行结果如上,通过反射的形式,访问到。

#反射

与java中反射类似,但C#里的反射在这里有新的用途,就是查看特性信息。直白的说,就是运行时获取类,类的属性,方法,甚至可以修改。有以下几项功能是一定的:

  • 它允许在运行时查看特性(attribute)信息。
  • 它允许审查集合中的各种类型,以及实例化这些类型。
  • 它允许延迟绑定的方法和属性(property)。
  • 它允许在运行时创建新类型,然后使用这些类型执行一些任务。

具体实现在应用的时候再更新吧

#属性

说白了属性和java里的封装方法getter和setter是类似的,只不过单独拿出来起了个名字而已

using System;
namespace tutorialspoint
{
   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();
       }
   }
}

不过比较奇怪的是,C#居然弄了一个抽象属性出来,不知道有啥用,感觉很鸡肋啊

using System;
namespace tutorialspoint
{
   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();
       }
   }
}

#索引器

##索引器定义

索引器(Indexer) 允许一个对象可以像数组一样被索引。当您为类定义一个索引器时,该类的行为就会像一个 虚拟数组(virtual array) 一样。您可以使用数组访问运算符([ ])来访问该类的实例。相当于比属性更加细粒度的访问实例

##索引器规范

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

感觉用途不是很多啊

#泛型和集合

都和java里差不多,暂时用不到很多,但C#的泛型有别于Java里的泛型,C#的泛型是真正的泛型,而java里的只是编译器的语法糖而已,在运行时候还是会被转换,只不过对于开发人员来说,便于理解而已,,并不会提高性能。

相关文章
|
19天前
|
Java C# 开发者
【干货】Java开发者快速上手.NET指南
【干货】Java开发者快速上手.NET指南
|
19天前
|
数据可视化 网络协议 C#
C#/.NET/.NET Core优秀项目和框架2024年3月简报
公众号每月定期推广和分享的C#/.NET/.NET Core优秀项目和框架(每周至少会推荐两个优秀的项目和框架当然节假日除外),公众号推文中有项目和框架的介绍、功能特点、使用方式以及部分功能截图等(打不开或者打开GitHub很慢的同学可以优先查看公众号推文,文末一定会附带项目和框架源码地址)。注意:排名不分先后,都是十分优秀的开源项目和框架,每周定期更新分享(欢迎关注公众号:追逐时光者,第一时间获取每周精选分享资讯🔔)。
|
1月前
|
存储 Java 计算机视觉
Java代码居然可以做出如此高级的图片编辑系统
Java代码居然可以做出如此高级的图片编辑系统
29 0
|
1月前
|
SQL 数据库 C#
C# .NET面试系列十一:数据库SQL查询(附建表语句)
#### 第1题 用一条 SQL 语句 查询出每门课都大于80 分的学生姓名 建表语句: ```sql create table tableA ( name varchar(10), kecheng varchar(10), fenshu int(11) ) DEFAULT CHARSET = 'utf8'; ``` 插入数据 ```sql insert into tableA values ('张三', '语文', 81); insert into tableA values ('张三', '数学', 75); insert into tableA values ('李四',
67 2
C# .NET面试系列十一:数据库SQL查询(附建表语句)
|
1月前
|
开发框架 算法 搜索推荐
C# .NET面试系列九:常见的算法
#### 1. 求质数 ```c# // 判断一个数是否为质数的方法 public static bool IsPrime(int number) { if (number < 2) { return false; } for (int i = 2; i <= Math.Sqrt(number); i++) { if (number % i == 0) { return false; } } return true; } class Progr
59 1
|
1月前
|
并行计算 安全 Java
C# .NET面试系列四:多线程
<h2>多线程 #### 1. 根据线程安全的相关知识,分析以下代码,当调用 test 方法时 i > 10 时是否会引起死锁? 并简要说明理由。 ```c# public void test(int i) { lock(this) { if (i > 10) { i--; test(i); } } } ``` 在给定的代码中,不会发生死锁。死锁通常是由于两个或多个线程互相等待对方释放锁而无法继续执行的情况。在这个代码中,只有一个线程持有锁,且没有其他线程参与,因此不
105 3
|
1月前
|
Java 编译器 程序员
Java中的异常处理:从基础到高级
【2月更文挑战第24天】本文将深入探讨Java中的异常处理,从基础的try-catch块到高级的异常处理策略。我们将了解如何使用Java的异常处理机制来提高代码的健壮性和可维护性,以及如何处理运行时和编译时的异常。
|
12天前
|
开发框架 前端开发 JavaScript
采用C#.Net +JavaScript 开发的云LIS系统源码 二级医院应用案例有演示
技术架构:Asp.NET CORE 3.1 MVC + SQLserver + Redis等 开发语言:C# 6.0、JavaScript 前端框架:JQuery、EasyUI、Bootstrap 后端框架:MVC、SQLSugar等 数 据 库:SQLserver 2012
|
1月前
|
并行计算 安全 Java
深入理解Java并发编程:从基础到高级
【2月更文挑战第30天】 本文将深入探讨Java并发编程的核心概念和技术,包括线程、锁、同步、并发集合等。我们将从基础知识开始,逐步深入到高级主题,如Fork/Join框架、CompletableFuture和反应式编程。通过本文,你将能够理解并发编程的重要性,掌握Java中实现高效并发的关键技术和方法。
|
1月前
|
开发框架 人工智能 .NET
C#/.NET/.NET Core拾遗补漏合集(持续更新)
C#/.NET/.NET Core拾遗补漏合集(持续更新)