html5风格网站特色瑞安门户网站建设
html5风格网站特色,瑞安门户网站建设,wordpress我爱水煮鱼,中国石油大学网站建设可能你对值类型和引用类型还不太了解。
值类型和引用类型#xff0c;是c#比较基础#xff0c;也必须掌握的知识点#xff0c;但是也不是那么轻易就能掌握#xff0c;今天跟着我一起来看看吧。
典型类型
首先我们看看这两种不同的类型有哪些比较典型的代表。
典型值类型…可能你对值类型和引用类型还不太了解。
值类型和引用类型是c#比较基础也必须掌握的知识点但是也不是那么轻易就能掌握今天跟着我一起来看看吧。
典型类型
首先我们看看这两种不同的类型有哪些比较典型的代表。
典型值类型
int, long, float, double等原始类型中表示数字的类型都是值类型表示时间的datetime也是值类型除此之外我们还可以通过关键字struct自定义值类型。
典型引用类型
原始类型中array, list, dictionary, queue, stack和string都是引用类型除此之外我们通过关键字class自定义引用类型。
基类
c#中所有的类型都最终继承自 Object 这是没有疑问的但是这其中还有些微区别。
值类型基类
对于值类型来说除了最终继承自Object还继承自ValueType继承链如下 添加图片注释不超过 140 字可选
但是请不要误解这里仅仅指的是值类型天然是ValueType但是不代表值类型能够这么声明
struct Struct1 : ValueType { }
这样是会引起编译错误的值类型不能继承任何其他类型值类型只能实现接口不能继承自其它类型。只有引用类型既可以实现接口也能继承自其它类型。顺便说一下还有一点比较重要的是ValueType重写了Object基类的 Equals 方法和 GetHashCode 方法所以当使用Equals比较两个值类型的时候系统会比较两个值类型的各个属性是否相等再返回结果这就是所谓的相等性 。与此相对引用类型在使用Equals的时候会在后台调用object.ReferenceEquals换言之引用类型在比较相等性的时候会考虑同一性 。
引用类型基类
对于引用类型就没有那么麻烦引用类型不会继承自ValueType。引用类型可以继承其他类型。
在内存中的表现
我们都知道C#将内存分为了两部分一个是Stack另外一个是Managed Heap。一般来说用于函数调用进栈函数返回出栈用的是Stack而当创造一个新的实例时会根据创建的实例属于值类型还是引用类型决定使用Stack还是Managed Heap。
值类型在内存中
当创建一个值类型对象时c#会在Stack上面创建一块空间这块空间就存放这个值类型对象。
int是一个典型的值类型如下语句
int age 10;
会存在于内存中的Stack上面。 添加图片注释不超过 140 字可选
如果把值类型的实例赋值给另外一个值类型那么效果就是复制一个新的值类型实例。
int myAge age; 添加图片注释不超过 140 字可选 引用类型在内存中
与值类型在内存中的表现不一样创建一个引用类型的实例不但会在Stack上面新建一个引用还会在Heap上面划分出内存以容纳该引用类型实例。用户在使用的时候通过Stack上面的变量间接引用该实例。
class Author { public string Name{get;set;} public int Age{get;set;} } Author author new Author(){Namedeatharthas, Age 32}; 添加图片注释不超过 140 字可选
注意看和值类型在内存中的区别引用类型通过Stack上的变量访问位于Heap上面的实例。
在赋值的时候拷贝的仅仅是Stack上面的变量新拷贝出来的对象和旧的对象指向的是同一块内存。
Author myAuthor author; 添加图片注释不超过 140 字可选
这个时候author和myAuthor指向同一块内存称为同一性通过调用
object.ReferenceEquals(myAuthor, author);
可以得到验证。
但可能有细心的朋友会有疑问了不是说int是值类型值类型是存在于Stack上面的吗为什么在author类里面它会在Heap里面呢赞一个细心值类型一般存在于Stack上面但如果某个值类型包含于引用类型那么它也会随着那个引用类型存放在Heap上面。
当参数时的行为区别
c#中的参数传递默认都是传值(by value)但是根据所传递对象是值类型还是引用类型它们的行为还是有所区别现在我们来看看。
值类型当参数
值类型当参数的时候传递到函数内部的是一份值类型的拷贝所以在函数内部修改这个拷贝不会影响原对象。除非我们在传递参数的时候使用了ref或者out。
引用类型当参数
如果参数是引用类型传递到函数内部的依然是一份拷贝但是这个拷贝是其在Stack上面的变量的拷贝就像上面的赋值那个例子。所以这个时候这份拷贝其实和原对象指向同一块内存指向同一性修改这个对象可以反映到原对象上面。
谨慎返回引用类型
编程是一项需要谨慎的工作有时候我们经常会犯一些错误而这些错误又是那么的不明显以至于不摔坑几次我们根本察觉不了考虑下面一个例子。
class People
{
public string Name{get;set;}
public int Age
{get;set;}
private People _Father null;
public People Father
{get{return _Father;}
}
public People(People father)
{_Father father;
}
public void ShowFather()
{Console.WriteLine(fathers name is Father.Name and his age is Father.Age);}
}
class Program{static void Main(string[] args)
{People father new People(null){Name father, Age 60
};People son new People(father);son.ShowFather(); Console.ReadLine();}
} 添加图片注释不超过 140 字可选
看起来没什么问题对吧Father没有提供setter似乎是安全的。但是我们试试下面的代码。
static void Main(string[] args){ People father new People(null){Name father, Age 60
};
People son new People(father);var f son.Father;f.NameChanged;son.ShowFather();Console.ReadLine();} 添加图片注释不超过 140 字可选
看发现了什么外部改变了本来应该被封装所保护的Father属性封装被破坏了
稍微一想我们应该能明白这个道理Father属性返回的拷贝的变量和原Father变量指向同一块实例。要想解决这个问题我们要么返回一个值类型要么返回一个全新的对象。修改Father属性如下:
public People Father
{
get
{
return new People(_Father._Father){
Name _Father.Name, Age _Father.Age
};}
}
再次测试 添加图片注释不超过 140 字可选
这次封装就没问题了。
总结
我们大概知道了值类型和引用类型的区别包括它们的行为在内存的居住方式以及使用引用类型时可能会遇到的暗坑希望大家通过阅读这篇文章能够加深一些对它们的了解少走一些弯路。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/87386.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!