一:概念

内存:用来存储程序信息的介质。

指针:指向一块内存区域,通过它可以访问该内存区域中储存的程序信息。(C#也是有指针的)

值类型:struct(整形、浮点型、decimal的内部实现都是struct)、enum、可空类型

引用类型:class、interface、delegate、数组、object、string。

二:深拷贝和浅拷贝的认识:

举个例子:

Myclass a=new Myclass();

Myclass b=a;

首先,深、浅拷贝与上面的语句并没有任何关系,要区分深、浅拷贝,关键要看“=”是如何重载的。

深拷贝:不管是值类型还是引用类型,都在内存中新建一块储存块,该储存块的内容(由b指向)与被拷贝的储存块(由a指向)的内容相同,并新建一个指针(b)指向该新建的储存块。所以对b的操作是不会影响a。

浅拷贝:对于值类型,拷贝一份值的副本;对于引用类型,拷贝一份指针的副本(该副本仍然指向原指针指向的内存块,即a、b指向同一块内存)。对b的值类型进行操作,不会影响a;对b的引用类型进行操作,会影响a。

对于浅拷贝,有一种奇怪的现象,即:若a中包含一个string类型的字段,对a进行浅拷贝,赋值给b,在b中改变这个string类型的字段,a中string类型字段不受影响。string类型明明是引用类型,按照上面的理解,修改b中的string字段,a中的string字段也该作出相应的改变,这是为什么呢?

我们不妨看看string的定义,会发现string被readonly关键字修饰了,即改变string的值时,就会重新分配内存空间。有兴趣的话可以了解一下“C#字符串不可变性”。

三:string

String是引用类型。究其原因,是因为string对象是不可变的,包括长度和其中任何字符都是不可以改变的。

关于不可变数据类型,请参考:https://www.cnblogs.com/mushroom/p/4373951.html

string 对象称为不可变的(只读),因为一旦创建了该对象,就不能修改该对象的值。有的时候看来似乎修改了,实际是string经过了特殊处理,每次改变值时都会建立一个新的string对象,变量会指向这个新的对象,而原来的还是指向原来的对象,所以不会改变。这也是string效率低下的原因。如果经常改变string的值则应该使用StringBuilder而不使用string。

在例子中str1=”ab”,这时在内存中就将“ab”存下来,如果再创建字符串对象,其值也等于“ab”,str2=”ab”,则并非再重新分配内存空间,而是将之前保存的“ab”的地址赋给str2的引用,这就能印证例子2中的结果。而当str1=”abc”其值发生改变时,这时检查内存,发现不存在此字符串,则重新分配内存空间,存储“abc”,并将其地址赋给str1,而str2依然指向“ab”的地址。可以印证例子中的结果。

String是引用类型,只是编译器对其做了特殊处理。

四:实例(原型模式)

1)浅拷贝:

声明一个将要被克隆的类 clsShallow 和它将要包含的引用类型成员clsRefSalary类clsShallow包含 CompanyName(静态字符串)、Age(值类型)、EmployeeName(字符串)、EmpSalary(引用类型)四个成员。

public class clsShallow
{
public static string CompanyName = "My Company";
public int Age;
public string EmployeeName;
public clsRefSalary EmpSalary; public clsShallow CreateShallowCopy(clsShallow inputcls)
{
return (clsShallow)inputcls.MemberwiseClone();
}
}
public class clsRefSalary
{
public clsRefSalary(int _salary)
{
Salary = _salary;
}
public int Salary;
}

再看如何调用:

 static void Main()
{
// Creates an instance of clsShallow and assign values to its fields.
clsShallow objshallow = new clsShallow();
objshallow.Age = 25;
objshallow.EmployeeName = "Ahmed Eid";
// add the ref value to the objshallow
clsRefSalary clsref = new clsRefSalary(1000);
objshallow.EmpSalary = clsref; // Performs a shallow copy of m1 and assign it to m2.
clsShallow m2 = objshallow.CreateShallowCopy(objshallow);
m2.Age = 20;
m2.EmployeeName = "jay"; // then modify the clsref salary value to be 2000
clsref.Salary = 2000;
// so the m1 object salary value become 2000 Console.WriteLine(m2 == objshallow);
Console.WriteLine(objshallow.EmpSalary.Salary);
Console.WriteLine(m2.EmpSalary.Salary);
Console.WriteLine(objshallow.Age);
Console.WriteLine(m2.Age);
Console.WriteLine(objshallow.EmployeeName);
Console.WriteLine(m2.EmployeeName);
}

最后看运行结果:

根据结果我们进行分析:

浅拷贝:

1、浅拷贝创建了类的一个新实例。(由对象的同一性得知:如果两个引用如m2 、 objshallow指向同一个对象的实例,则(m2 == objshallow)为true,而结果显示为  false,所以m2 和objshallow分别指向不同的实例,而objshallow引用所指向的实例是新创建的。

2、对于对象(clsShallow)中的引用类型成员(clsRefSalary),引用被复制,但引用的实例没有被复制,即新创建实例中的引用成员(m2.EmpSalary)等于原实例的引用成员(objshallow.EmpSalary)。 因为改变 clsref.Salary 等于2000后,objshallow.EmpSalary 和m2.EmpSalary的Salary都改变了。其实可通过Console.WriteLine(objshallow.EmpSalary == m2.EmpSalary) 输出为true来解释。

3、值类型字段逐位复制到新实例。即改变m2.Age不影响objshallow.Age值。有人要问,string 为引用类型,为什么改变m2.EmployeeName = "jay"而objshallow.EmployeeName = "Ahmed Eid"没变呢?这是因为:字符串具有恒等性,一个字符串一旦被创建,我们就不能再将其变长、变短、或者改变其中的任何字符。

2) 深拷贝:

修改代码如下:

static void Main()
{
clsDeep objdeep = new clsDeep();
objdeep.Age = 25;
objdeep.EmployeeName = "Ahmed Eid"; // add the ref value
clsRefSalary clsref = new clsRefSalary(1000);
objdeep.EmpSalary = clsref; // Performs a shallow copy of m1 and assign it to m2.
clsDeep m2 = objdeep.CreateDeepCopy(objdeep); // then modify the clsref salary value to be 2000
clsref.Salary = 2000; // so the m1 object salary value become 2000
int EmpSalary = objdeep.EmpSalary.Salary;
m2.Age = 20;
m2.EmployeeName = "jay"; // then modify the clsref salary value to be 2000
clsref.Salary = 2000;
// so the m1 object salary value become 2000
Console.WriteLine(m2 == objdeep);
Console.WriteLine(objdeep.EmpSalary.Salary);
Console.WriteLine(m2.EmpSalary.Salary);
Console.WriteLine(objdeep.EmpSalary == m2.EmpSalary);
Console.WriteLine(objdeep.Age);
Console.WriteLine(m2.Age);
Console.WriteLine(objdeep.EmployeeName);
Console.WriteLine(m2.EmployeeName);
} [Serializable]
// serialize the classes in case of deep copy
public class clsDeep
{
public static string CompanyName = "My Company";
public int Age;
public string EmployeeName;
public clsRefSalary EmpSalary;
public clsDeep CreateDeepCopy(clsDeep inputcls)
{
MemoryStream m = new MemoryStream();
BinaryFormatter b = new BinaryFormatter();
b.Serialize(m, inputcls);
m.Position = 0;
return (clsDeep)b.Deserialize(m);
}
} [Serializable]
public class clsRefSalary
{
public clsRefSalary(int _salary)
{
Salary = _salary;
}
public int Salary;
}

记得加命名空间

using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

查看结果:

深拷贝:

1、深拷贝创建了类的一个新实例

2、对于实例中的引用类型成员,创建引用类型成员对象的新副本。 ( objshallow.EmpSalary != m2.EmpSalary)

3、值类型字段逐位复制到新实例

实,浅拷贝和深拷贝的本质区别是实例中的引用类型成员如何拷贝, 浅拷贝复制引用,深拷贝创建新实例。

注:无论浅、深拷贝,静态成员都不会复制,因为静态成员属于类成员。

3)深复制方法

/// <summary>
/// Perform a deep Copy of the object.
/// </summary>
/// <typeparam name="T">The type of object being copied.</typeparam>
/// <param name="source">The object instance to copy.</param>
/// <returns>The copied object.</returns>
public static T Clone<T>(this T source)
{
if (!typeof(T).IsSerializable)
{
throw new ArgumentException("The type must be serializable.", "source");
} // Don't serialize a null object, simply return the default for that object
if (Object.ReferenceEquals(source, null))
{
return default(T);
} IFormatter formatter = new BinaryFormatter();
Stream stream = new MemoryStream();
using (stream)
{
formatter.Serialize(stream, source);
stream.Seek(0, SeekOrigin.Begin);
return (T)formatter.Deserialize(stream);
}
}

最新文章

  1. Memcached初识
  2. SVG图案填充-Pattern
  3. 如何用php生成1-10之间的不重复随机数
  4. linux中用户的主目录~
  5. SQL Server优化技巧之SQL Server中的&quot;MapReduce&quot;
  6. Android配置----adb工具的使用
  7. HDU 5137 How Many Maos Does the Guanxi Worth
  8. [Unity菜鸟] FBX模型动画提取
  9. onTextChanged参数解释及实现EditText字数监听
  10. kafka相关应用
  11. C++单链表的创建与操作
  12. 本地拦截genymotion或者Android模拟器的网络请求
  13. 跨境移动互联网的魅力演绎,hao123无论成就下一个条目?
  14. Mycat 安装配置
  15. 软工+C(2017第8期) 提问与回复
  16. Android 开发笔记___Activity的生命周期
  17. Servlet开篇
  18. Java:配置环境(Mac)——Tomcat
  19. Eclipse Maven profiles 多环境配置,测试环境与开发环境分开打包
  20. HDU 4864 Task(贪心)

热门文章

  1. C#: 获取当前路径不要用Environment.CurrentDirectory
  2. c#中取整方式
  3. Angular6 学习笔记——组件详解之模板语法
  4. 创建自己的Code Snippet(代码模板)
  5. JVM内存回收区域+对象存活的判断+引用类型+垃圾回收线程
  6. Socket编程入门
  7. arya-sites模块的主要类
  8. JS弹出对话框函数alert(),confirm(),prompt()
  9. ajax请求失败 chrome报错net::ERR_INCOMPLETE_CHUNKED_ENCODING 问题原因
  10. jmeter-server中启动后端口总是不断在变化