【C#学习笔记】引用类型(2)

在这里插入图片描述

文章目录

  • Object
    • Equals
    • GetType
    • ToString
    • GetHashCode
  • string
    • 逐字文本
    • 复合格式字符串
    • 字符串内插
  • StringBuilder
    • StringBuilder 的工作原理
    • StringBuilder提供的方法
    • 访问字符
    • 迭代字符
    • 查询字符
  • dynamic


Object

支持 .NET 类层次结构中的所有类,并为派生类提供低级别服务。 这是所有 .NET 类的最终基类;它是类型层次结构的根。

简单来说,它是万能的,它是所有类型的父类。因为.NET 中的所有类都派生自 Object,因此 Object 类中定义的每个方法都可用于系统中的所有对象。

在 Object 类中提供了 4 个常用的方法,即 Equals、GetHashCode、GetType 以及 ToString 方法。

Equals

int a = 1;
int b = 1;
if (a.Equals(b))
{
  Debug.Log("111"); -- 输出111
}

Person a = new Person();
Person b = 1;
if (a.Equals(b))
{
  Debug.Log("111"); -- 输出111
}

Equals是相等判断,与==相同,对于值类型的判断是否值相同,而对于引用类型则判断是否引用相同。

GetType

用于获取当前实例的类型,返回值为 System.Type 类型。GetType 方法不含任何参数,是非静态方法。

使用Object.GetType()来返回对象的类型x.GetType()和typeof()的区别是,GetType()是object的方法,可以用于所有变量后,以获取它们的类型。和typeof(xxx)内部只能放类型而不能放变量名。

ToString

将对象转换为其字符串表示形式,使其适合显示。

上述三种方法是可以重载,重写的。

GetHashCode

返回对象的哈希值,每个对象的哈希值都是固定的。该方法不含有任何参数,并且不是静态方法,因此需要使用实例来调用该方法。由于该方法是在 Object 类中定义的,因此任何对象都可以直接调用该方法。


string

字符串类型string表示零个或多个 Unicode 字符的序列。 比较特殊的是,尽管string是引用类型,但是使用==来比较时却是值类型的比较。需要注意的是,string是不可变类型,这意味着每次我们修改字符串string的操作实际上都是创建了一个新的字符串。

逐字文本

使用@关键字标识该字符串为逐字文本,将不会识别转义符

@"""Ahoy!"" cried the captain." // "Ahoy!" cried the captain.
@"c:\Docs\Source\a.txt"  // rather than "c:\\Docs\\Source\\a.txt"

复合格式字符串

使用String.Format方法将变量复合到格式项内,其中括号内的数字代表了对应的变量索引,而:后面代表变量的指定类型。

String.Format("Name = {0}, hours = {1:hh}", name, DateTime.Now);

多个相同索引也可以同时存在

string multiple = String.Format("0x{0:X} {0:E} {0:N}",
                                Int64.MaxValue);
Console.WriteLine(multiple);
// The example displays the following output:
//      0x7FFFFFFFFFFFFFFF 9.223372E+018 9,223,372,036,854,775,807.00

字符串内插

使用$关键字标识字符串内插

string name = "Mark";
var date = DateTime.Now;
// Composite formatting:
Console.WriteLine("Hello, {0}! Today is {1}, it's {2:HH:mm} now.", name, date.DayOfWeek, date);
// String interpolation:
Console.WriteLine($"Hello, {name}! Today is {date.DayOfWeek}, it's {date:HH:mm} now.");

(更多用法请阅读官方文档,尤其是string类的方法,尴尬的是string类的方法特别多,但是String大多数情况下却被StringBuilder完爆)


StringBuilder

使用命名空间System.Text来引入该类型

StringBuilder可以说是String的完全上位替代,这是一个可变的字符串类。 可变性意味着,创建类的实例后,可以通过追加、删除、替换或插入字符对其进行修改。由于String每次修改时都需要产生一个新的字符串,这也就导致了对其进行操作可能产生的一些内存消耗问题。所以对于需要操作的字符串,我们会选择StringBuilder,不过性能取决于字符串的大小、要为新字符串分配的内存量、执行代码的系统以及操作的类型。

请考虑在以下情况下使用 String 类:

  • 当代码对字符串进行的更改数较小时。 在这些情况下, StringBuilder 可能会提供微不足道的性能改进,因此可以直接使用String。
  • 执行固定数量的串联操作时,尤其是字符串文本。 在这种情况下,编译器可能会将串联操作合并到单个操作中。
  • 在生成字符串时必须执行广泛的搜索操作时。 类 StringBuilder 缺少搜索方法,例如 IndexOf 或 StartsWith。 对于这些操作,必须将 StringBuilder对象转换为String , 这可以抵消使用 StringBuilder的性能优势。 有关详细信息,请参阅 在 StringBuilder 对象中搜索文本 部分。

请考虑在以下情况下使用 StringBuilder 类:

  • 如果预期代码在设计时对字符串进行未知数量的更改, 例如,使用循环连接包含用户输入的随机数量的字符串时。
  • 预期代码对字符串进行大量更改时。

总的来说,一些短平快的操作,或者需要涉及串联字符串,或是查询整个字符串的时候更适合String。如果一些需要频繁更改,或者动态修改的字符串更适合StringBuilder

StringBuilder 的工作原理

StringBuilder是如何动态修改字符串长度的?假设有一个字符串长度为12的stringBuilder,如果我们需要Append成一个length =20的字符串,那么首先StringBuilder会把字符串丢入这个长度为16的缓冲区,当长度超过缓冲区的长度时,则意味着需要更大的缓冲区,则StringBuilder会找一个缓冲区大小翻一倍的新缓冲区(现在是32了)。然后把旧缓冲区的值复制过去,并加入那些超过原长度而未被存入旧缓冲区的新字符。如果还是超过就重复上述过程,直到存储完毕为止。(如果超出了设定最大容量或者内存没有多余空间了则报错)

public class Example
{
   public static void Main()
   {
      StringBuilder sb = new StringBuilder();
      ShowSBInfo(sb);
      sb.Append("This is a sentence.");
      ShowSBInfo(sb);
      for (int ctr = 0; ctr <= 10; ctr++) {
         sb.Append("This is an additional sentence.");
         ShowSBInfo(sb);
      }   
   }
   
   private static void ShowSBInfo(StringBuilder sb)
   {
      foreach (var prop in sb.GetType().GetProperties()) {
         if (prop.GetIndexParameters().Length == 0)
            Console.Write("{0}: {1:N0}    ", prop.Name, prop.GetValue(sb));
      }
      Console.WriteLine();
   }
}
// The example displays the following output:
//    Capacity: 16    MaxCapacity: 2,147,483,647    Length: 0
//    Capacity: 32    MaxCapacity: 2,147,483,647    Length: 19
//    Capacity: 64    MaxCapacity: 2,147,483,647    Length: 50
//    Capacity: 128    MaxCapacity: 2,147,483,647    Length: 81
//    Capacity: 128    MaxCapacity: 2,147,483,647    Length: 112
//    Capacity: 256    MaxCapacity: 2,147,483,647    Length: 143
//    Capacity: 256    MaxCapacity: 2,147,483,647    Length: 174
//    Capacity: 256    MaxCapacity: 2,147,483,647    Length: 205
//    Capacity: 256    MaxCapacity: 2,147,483,647    Length: 236
//    Capacity: 512    MaxCapacity: 2,147,483,647    Length: 267
//    Capacity: 512    MaxCapacity: 2,147,483,647    Length: 298
//    Capacity: 512    MaxCapacity: 2,147,483,647    Length: 329
//    Capacity: 512    MaxCapacity: 2,147,483,647    Length: 360

StringBuilder提供的方法

可以进行单独的方法调用并忽略返回值,如以下示例所示。

using System;
using System.Text;

public class Example
{
   public static void Main()
   {
      StringBuilder sb = new StringBuilder();
      sb.Append("This is the beginning of a sentence, "); 
      sb.Replace("the beginning of ", ""); //替换所有字符A为字符B
      sb.Insert(sb.ToString().IndexOf("a ") + 2, "complete ");
      sb.Replace(",", "."); 
      Console.WriteLine(sb.ToString()); //只有在必须接受string类型时再转化为string
   }
}
// The example displays the following output:
//        This is a complete sentence.

可以在单个语句中调用一系列方法。 如果要编写链接连续操作的单个语句,这可以很方便。 以下示例将上一示例中的三个方法调用合并到一行代码中。

using System;
using System.Text;

public class Example
{
   public static void Main()
   {
      StringBuilder sb = new StringBuilder("This is the beginning of a sentence, ");
      sb.Replace("the beginning of ", "").Insert(sb.ToString().IndexOf("a ") + 2, 
                                                 "complete ").Replace(",", ".");
      Console.WriteLine(sb.ToString());
   }
}
// The example displays the following output:
//        This is a complete sentence.

访问字符

访问字符在我看来是StringBuilder的一大痛点。StringBuilder没有提供访问其内部字符的方法,而想要访问其中的某个字符却没那么简单,因为缓冲区的内存是不连续的,如果想要找到某个字符,我们就需要遍历整个缓冲区。因此较好的方法是通过ToString方法将其转化为String类型之后使用char[Index]去访问对应字符。

迭代字符

当迭代StringBuilder的字符的时候,应当注意:即使对于大型“区块” StringBuilder 对象,使用 Chars[] 属性进行基于索引的访问一个或少量字符的性能影响可以忽略不计;通常,这是 一个 O (n) 操作。 当迭代 StringBuilder 对象中的字符时,会对性能造成显著的影响,这是 O(n^2) (遍历n个字符*缓存区容量n)操作。

因此当我们需要迭代StringBuilder的字符时,较好的方法还是通过ToString方法将其转化为String类型之后使用char[Index]去访问对应字符。

查询字符

在StringBuilder中并没有提供查询字符的方法,想实现查询字符,也只能转为String,然后用String.IndexOf或者String.StartWith方法查找对应的字符或字符串。

由于String和StringBuilder提供的方法太多,因此此处无法深入,推荐阅读官方文档


dynamic

最后稍微了解一下dynamic动态类型。dynamic本身也是一个Object。在大多数情况下,dynamic 类型与 object 类型的行为类似。 具体而言,任何非 Null 表达式都可以转换为 dynamic 类型。 dynamic 类型与 object 的不同之处在于,编译器不会对包含类型 dynamic 的表达式的操作进行解析或类型检查。 编译器将有关该操作信息打包在一起,之后这些信息会用于在运行时评估操作。 在此过程中,dynamic 类型的变量会编译为 object 类型的变量。 因此,dynamic 类型只在编译时存在,在运行时则不存在。

dynamic的特殊就在于它是不会在编译时被解析的,因此不会进行任何的安全检查。因此即使定义了错误的dynamic,编译器也不会报错。而只有在运行时出现错误才会报错。

其次,由于dynamic的本质是Object,它也可以和任何类型进行隐式转换。而这也是它的最大优点。例如:

dynamic x = 10; //此时x为int
x = x + "Hello"; // x 现在是一个字符串
x = x.ToUpper(); // x 仍然是一个字符串
x = 8;  // x 现在保存的是一个int类型的变量
x = x * 8; // x现在仍然是int

在上例中,我们定义x为dynamic,可以看出来它对应应当是int型,然后我们将其转化为字符串,然后对字符串进行操作。随后又把x赋值为了int类型的。x在整个程序中动态的变动它的类型。而这是var做不到的,因为var关键字下编译器会自动地推断它的类型,那它就是一个静态类,一般没有显示转换的前提下我们是不能进行类型转换的。

如果只用静态类想实现则需要新创建其中设计到的静态类型对应的变量,而如果想让静态类型变量x实现上述过程只会更加复杂:

int x=10;
String y = x.ToString();
y=y+"Hello";
y = y.ToUpper();
x = 8;
x = x* 8

而dynamic的动态类型实际和某些脚本语言的变量性质是非常相似的。因此我们也使用dynamic类型来与脚本语言进行对接。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/58621.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

物理机是什么?有什么优势?可以上堡垒机吗?

你知道物理机是什么&#xff1f;有什么优势&#xff1f;可以上堡垒机吗&#xff1f;今天我们就来简单聊聊。 物理机是什么&#xff1f; 物理机是相对于虚拟机而言的对实体计算机的称呼。物理机提供给虚拟机以硬件环境&#xff0c;有时也称为“寄主”或“宿主”。 物理机有什么…

万界星空科技/免费开源MES系统/免费仓库管理

仓库管理&#xff08;仓储管理&#xff09;&#xff0c;指对仓库及仓库内部的物资进行收发、结存等有效控制和管理&#xff0c;确保仓储货物的完好无损&#xff0c;保证生产经营活动的正常进行&#xff0c;在此基础上对货物进行分类记录&#xff0c;通过报表分析展示仓库状态、…

软件设计师(六)结构化开发方法

结构化方法由结构化分析、结构化设计、结构化程序设计构成&#xff0c;它是一种面向数据流的开发方法。 分类说明结构化分析&#xff08;SA&#xff09;根据分解与抽象的原则&#xff0c;按照系统中数据处理的流程&#xff0c;用数据流图来建立系统的功能模型&#xff0c;从而…

7种有效安全的网页抓取方法,如何避免被禁止?

网页抓取是一种从互联网上抓取网页内容的过程&#xff0c;但在网络抓取种相信您也经常遇到障碍&#xff1f;尤其是做跨境业务的&#xff0c;在抓取国外的网站时更有难度。但我们站在您的立场上&#xff0c;提供七种有效的方法来进行网页抓取而不被阻止&#xff0c;最大限度地降…

python可以做哪些小工具,python可以做什么小游戏

大家好&#xff0c;小编来为大家解答以下问题&#xff0c;python可以做什么好玩的&#xff0c;python可以做什么小游戏&#xff0c;今天让我们一起来看看吧&#xff01; 最近有几个友友问我说有没有比较好玩的Python小项目来练手&#xff0c;于是我找了几个比较有意思的给他们&…

CUDA编程

银河系CUDA编程指南(3)——矩阵乘法的分块实现 银河系CUDA编程指南(3)——矩阵乘法的分块实现 - 知乎0 写在前面前面一节实现了一个朴素的GPU矩阵乘法&#xff0c;效果和使用cublas库差距极大。其中一个原因就是因为对全局存储器 ( global memory) 的访问。全局内存通常使用DR…

亚马逊关键词的作用有哪些?

亚马逊关键词在平台上扮演着重要的作用&#xff0c;涵盖了消费者、卖家和整个平台的多个方面&#xff1a; 1、消费者的作用&#xff1a; 帮助消费者快速找到所需商品&#xff1a;通过输入关键词&#xff0c;消费者可以迅速找到感兴趣的商品&#xff0c;节省时间和精力。 支持…

百分点科技跻身中国智慧应急人工智能解决方案市场前三

近日&#xff0c; 全球领先的IT市场研究和咨询公司IDC发布了《中国智慧应急解决方案市场份额&#xff0c;2022》报告&#xff0c;数据显示&#xff0c;2022年中国智慧应急整体市场为104亿元人民币。其中&#xff0c;智慧应急人工智能解决方案子市场备受关注&#xff0c;百分点科…

day1-牛客67道剑指offer-JZ4 JZ6 JZ7 JZ9 JZ11 JZ69 JZ70 替换空格 斐波那契数列及其变形 左移/右移运算符

文章目录 1. JZ4 二维数组中的查找暴力法右上角往左下角逼近二分查找-左闭右开区间 2. 替换空格3. JZ6 从尾到头打印链表4. JZ7 重建二叉树思路1哈希加速 5. JZ9 用两个栈实现队列6. JZ11 旋转数组的最小数字常规遍历二分法 7. 斐波那契数列动态规划递归 8. JZ69 跳台阶动态规划…

PS - Photoshop 实现涂抹功能 (橡皮擦、图章、吸管、画笔)

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/131997323 在 Photoshop 中&#xff0c;橡皮擦工具&#xff0c;以及吸管工具和画笔工具可以配合使用&#xff0c;实现涂抹功能&#xff0c;再通过…

AMEYA360:瑞萨电子MCU和MPU产品线将支持Microsoft Visual Studio Code

全球半导体解决方案供应商瑞萨电子宣布其客户现可以使用Microsoft Visual Studio Code&#xff08;VS Code&#xff09;开发瑞萨全系列微控制器&#xff08;MCU&#xff09;和微处理器&#xff08;MPU&#xff09;。瑞萨已为其所有嵌入式处理器开发了工具扩展&#xff0c;并将其…

zookeeper入门学习

zookeeper入门学习 zookeeper应用场景 分布式协调组件 客户端第一次请求发给服务器2&#xff0c;将flag值修改为false&#xff0c;第二次请求被负载均衡到服务器1&#xff0c;访问到的flag也会是false 一旦有节点发生改变&#xff0c;就会通知所有监听方改变自己的值&#…

ConcurrentHashMap 的简单介绍

ConcurrentHashMap是Java集合框架中的一个并发容器&#xff0c;它是线程安全的哈希表的实现。它被设计为比Hashtable和SynchronizedMap&#xff08;通过使用同步方法或块来保证线程安全&#xff09;更高效和可扩展的替代品。 ConcurrentHashMap具有以下特点&#xff1a; 线程…

Docker安装RabbitMQ镜像

步骤1&#xff1a;拉取镜像 docker pull rabbitmq:management 步骤2&#xff1a;运行 docker run -d –-name rabbit -e RABBITMQ_DEFAULT_USERadmin -e RABBITMQ_DEFAULT_PASSadmin -p 15672:15672 -p 5672:5672 -p 25672:25672 -p 61613:61613 -p 1883:1883 rabbitmq:mana…

Windows同时安装两个版本的JDK并随时切换,以JDK6和JDK8为例,并解决相关存在的问题(亲测有效)

Windows同时安装两个版本的JDK并随时切换&#xff0c;以JDK6和JDK8为例&#xff0c;并解决相关存在的问题&#xff08;亲测有效&#xff09; 1.下载不同版本JDK 这里给出JDK6和JDK的百度网盘地址&#xff0c;具体安装过程&#xff0c;傻瓜式安装即可。 链接&#xff1a;http…

Redis学习总结

Redis学习总结 文章目录 Redis学习总结Radis基本介绍docker的安装基本数据结构通用命令字符型key的层次结构Hash类型Listset sortedset集合redis的java客户端jedis的使用jedis连接池的配置 SpringDataRedis自定义redistemplate的序列化与反序列化方式stringtemplate的使用 redi…

windows创建占用特定端口程序

默认情况下&#xff0c;远程桌面使用的是3389端口。如果您想将远程桌面端口更改为8005&#xff0c;以达到模拟程序占用端口8005的情况&#xff0c;可以执行以下操作&#xff1a; 如执行以下命令&#xff0c;则1&#xff0c;2&#xff0c;3步相同操作可以跳过&#xff0c;直接往…

【Java】Springboot脚手架生成初始化项目代码

Springboot配置生成初始化项目代码可以通过mvn的mvn archetype:generate 和阿里云原生应用脚手架&#xff08;地址&#xff09;、spring官方提供的start初始化生成页面(地址&#xff09;。 1、mvn archetype:generate 通过mvn选择对应的脚手架可以快速生成初始化代码&#xf…

一次有趣的Webshell分析经历

一次有趣的Webshell分析经历 1.拉取源代码2.解密后门代码3.分析webshell逻辑4.分析404的原因5.附&#xff1a;格式化后的php代码 1.拉取源代码 在对某目标做敏感目录收集时发现对方网站备份源代码在根目录下的 backup.tar.gz&#xff0c;遂下载&#xff0c;先使用D盾分析有没有…

shiro快速入门

文章目录 权限管理什么是权限管理&#xff1f;什么是身份认证&#xff1f;什么是授权&#xff1f; 什么是shiro&#xff1f;shiro的核心架构shiro中的三个核心组件 shiro中的认证shiro中的授权shiro使用默认Ehcache实现缓存shiro使用redis作为缓存实现 权限管理 什么是权限管理…