首页 > 编程语言 >关于C#方法中引用类型参数传递

关于C#方法中引用类型参数传递

时间:2023-02-17 18:00:40浏览次数:41  
标签:AssignmentPerson Name C# Age 参数传递 Person 引用 np 方法

本文叙述的问题的根源在于对C#基础知识掌握不牢固,从而在遇到难以理解的问题时浪费了大量时间;
在此也警示自己,该啃啃基础书籍了!
话不多说,先上代码:

先看问题

services.AddEasyCaching(option =>
{
    option.UseHybrid(config =>
    {
        .....
    })
    .WithZookeeeperBus(busConf =>
    {
        // 方式1
        busConf.ConnectionString = "192.168.3.86:2181";
        // 方式2
        busConf = new ZkBusOptions
        {
            ConnectionString = "192.168.3.86:2181",
        };
    });
});

这是我在使用EasyCaching时的一段注册代码,在配置Zookeeeper Bus时调用了WithZookeeeperBus(Action<ZkBusOptions>)拓展方法,并采用了如上两种赋值方式,看似都能正常配置,但实际不尽人意:
方式1:配置正常;
方式2:配置无效,最终ConnectionString=null

what?肯定是编译器问题!( 确信
此时我的心情极其复杂,这两种赋值不是一样的?

问题在哪?

一开始,我甚至怀疑是自己对Action<T>的理解不到位,存在某种机制导致的问题,但事实证明,饭可以乱吃,锅不能乱甩;
每每想起这,不由得老脸一红!

问题在这

实则问题是在最基础的方法传参问题;
咱们可以先理解一下方法传参存在哪几种情况,以及情况对应传参方式;
在C#参数传递分为如下四种:

  • 值类型的值传递(将值类型的副本传递给方法)
  • 值类型的引用传递(将值类型本身传递给方法,例如:使用了ref int a
  • 引用类型的值传递(将引用的副本传递给方法 )
  • 引用类型的引用传递(将引用本身传递给方法,例如:使用了ref object o

此时,如果你已经悟了,那文章到此结束,还一知半解的,请继续往下看;

再细一点

先看看如下代码:

void Main()
{
	var p = new Person { Name = "jason", Age = 19 };
    // 赋值方法 1
	AssignmentPerson_1(p);
    Console.WriteLine($"Name: {p.Name}; Age: {p.Age}");

    // 赋值方法 2
    AssignmentPerson_2(p);
	Console.WriteLine($"Name: {p.Name}; Age: {p.Age}");
}

public void AssignmentPerson_1(Person t)
{
	var np = new Person { Name = "jack", Age = 18 };
	t = np;
}

public void AssignmentPerson_2(Person t)
{
	var np zhanzhi

很显然,在本文起始的教训下,答案是明显,会输出如下:
Name = "jason"; Age = 19
Name = "jack"; Age = 18

首先,在main中创建了p,假设p在栈中的地址为0x0001,栈值为指向堆中实例的地址0x00D1

赋值方法-1

然后,开始调用AssignmentPerson_1(Person t),并传入p
此时,不是直接将 p(栈地址:0x0001)传入方法,而是拷贝了一份p(栈地址:0x0005),并且同时将栈值赋为0x00D1,传入方法中;
所以,AssignmentPerson_1(Person t)t的地址为0x0005

最后,新建np,栈地址为0x000A,栈值为指向堆中实例的地址0x00D5
并将t = npt的栈值被替换了0x00D1 -> 0x00D5

最终,p的栈值还是0x00D1,并且0x00D1中的堆值也并未发生变化,所以赋值无效;

赋值方法-2

同理,当调用AssignmentPerson_2(Person t)时,同样传入p,同样新建np
但是,并没有替换t的栈值,它仍旧与p指向的堆地址相同,为0x00D1;
此时赋值操作只是替换了堆值中实例的属性值:t.Name = np.Namet.Age = np.Age

所以,t指向的堆值发生了变化, tp又指向地址相同,p的实例属性值也就发生了变化;

总结

该读一本《CLR via》了!

参考

1-关于C#函数对象参数传递的问题
2-彻底澄清:C#方法参数

标签:AssignmentPerson,Name,C#,Age,参数传递,Person,引用,np,方法
From: https://www.cnblogs.com/memoyu/p/17131079.html

相关文章

  • ISC DHCP 分配IP流程分析
    概述在Linux的世界中,ISCDHCP被广泛应用。因为ISCDHCP的版权是允许在保留其版权声明的基础上,使用,复制,修改其源代码。对于Linux开发人员来说,在掌握了ISCDHCP分配IP的流程......
  • 在centos stream 9上搭建k8s最新版本(当前:v1.26.1)集群环境
    为了尽可能契合生产环境的部署情况,这里用kubeadm安装集群,同时方便跟随笔记一步步实践的过程,也更加了解k8s的一些特性和基础知识。先决条件这里将通过虚拟机安装3台centos......
  • 外部连接不上 docker内的Mysql,telnet不通3306
    本机vm打开虚拟机后,自动启动mysql,查看容器运行一切正常:dockerps-a 所有映射的端口,在外部都telnet不通,比如3306、6379等都不行。想着在别人都ok的,在我这里不行,问题......
  • javascript 高级编程系列 - 迭代器/生成器
    1.迭代器(Iterator)特殊对象,具有迭代过程的接口next()方法每次调用next()方法,返回一个结果对象结果对象有两个属性value(任何类型)和done(布尔类型)当集合的值返回完时......
  • 定时任务corn表达式解析
    corn分为两种,长度为6和长度为7的情况秒分时日月周秒分时日月周年符号:秒分时:,*-/日:,*-/+?W(工作日)L(最后)C......
  • vue2 vue-router.esm.js:16 [vue-router] Failed to resolve async component default
    敢信,晚上加班找这个错误,TMD找了二小时,网上各种百度。。。。。。原因竟然是这个ProductCategory组件,没有import进来,而components中却引用了!!!!低级错误,粗心问题!!!这也再次证......
  • 国内OpenAI充值,购买ChatGPt plus一站式流程(使用depay注册海外支付(万事达)和OKX(欧易)进行
    OpenAI的ChatGPT已经推出,但是对国内有限制,购买使用十分不便,经过摸索研究终于购买成功,记录分享一下在国内购买的方法,两个链接放在前面方便取用。depay快捷跳转链接:https:/......
  • DHCP源码分析-dhcp模块
    一,DHCP函数流程   函数voiddhcp(structpacket*packet)是处理DHCP包的入口函数,在进入这个函数的时候,对包的解析已经完成,已经将包的内容转换成内部结构s......
  • 关于ChatGPT,我们到底在担心什么?
    “ChatGPT已对教育产生了巨大冲击”“ChatGPT对程序员造成了哪些影响”“ChatGPT会取代人类的哪些工作?”“谷歌宣布推出类ChatGPT产品Bard”“Bing新版本引入ChatGP......
  • ISC DHCP租约分析
    租约状态转换DHCP服务系统中的租约共有八种状态:空闲状态、预留状态、活跃状态、过期状态、释放状态、废弃状态、重置状态、备份状态。重置状态和备份状态为启动FAILOVER模......