C#弗成變類型深刻解析。本站提示廣大學習愛好者:(C#弗成變類型深刻解析)文章只能為提供參考,不一定能成為您想要的結果。以下是C#弗成變類型深刻解析正文
學過C#的人都曉得string類型,然則string作為一種特別的援用類型還有一個主要的特點就是恆定性,或許叫弗成變性,即Immutable。作為弗成變類型,最重要的特征表示是:一旦創立,只需修正,就會在托管堆上創立一個新的對象實例,並且和上一個對象實例是相鄰的,在托管堆上分派到一塊持續的內存空間。
那末為何須要弗成變類型呢?
在多線程情形下,一個線程,因為各種緣由(好比異常)只修正了一個變量所代表類型的部門成員的值,這時候候,另外一個過程出去,也拜訪這個變量,第二個過程拜訪到的變量成員,一部門成員照樣本來的值,另外一部門成員的值是第一個線程修正的值,如許就湧現了"數據紛歧致"。而弗成變類型就是為懂得決在多線程前提下的"數據紛歧致"的成績。
固然,字符串的弗成變性或恆定性,不只處理了"數據紛歧致"的成績,還為字符串的"駐留"供給了條件,如許才可以把分歧的字符串和托管堆上的內存地址以鍵值對的情勢放到全局哈希表中。
1、親眼目擊"數據紛歧致":
對Student的Score屬性,在賦值的時刻加上檢測,檢測能否是2位數整數。
public struct Student
{
private string name;
private string score;
public string Name
{
get { return name; }
set { name = value; }
}
public string Score
{
get { return score; }
set
{
CheckScore(value);
score = value;
}
}
//檢測分數能否是2位數整數
private void CheckScore(string value)
{
string pattern = @"\d{2}";
if (!Regex.IsMatch(value, pattern))
{
throw new Exception("不是有用分數!");
}
}
public override string ToString()
{
return String.Format("姓名:{0},分數:{1}", name, score);
}
}
在主法式中有意制作出一個異常,目標是只對一個變量所代表類型的某些成員賦值。
static void Main(string[] args)
{
Student student = new Student();
student.Name = "張三";
student.Score = "80";
Console.WriteLine(student.ToString());
try
{
student.Name = "李四";
student.Score = "8";
}
catch (Exception)
{
throw;
}
Console.WriteLine(student.ToString());
Console.ReadKey();
}
打斷點,運轉,發明Student類型的student變量,在第二次賦值的時刻,把student的Name屬性值改了過去,而student的Score屬性,因為產生了異常,沒有修正過去。這就是"數據紛歧致"。
以下圖所示:

2、著手設計弗成變類型
1.弗成變類型的2個特征:
①對象的原子性:要末不改,要改就把一切成員都改,從而創立新的對象。
②對象的常量性:對象一旦創立,就不克不及轉變狀況,即不克不及轉變對象的屬性,只能創立新的對象。
2.遵守以上弗成變類型的2個特點
①在結構函數中對一切字段賦值。
②將屬性中的set拜訪器刪除。
class Program
{
static void Main(string[] args)
{
Student student = new Student("張三", "90");
student = new Student("李四","80");
Console.WriteLine(student.ToString());
Console.ReadKey();
}
}
public struct Student
{
private readonly string name;
private readonly string score;
public Student(string name, string score)
{
this.name = name;
this.score = score;
}
public string Name
{
get { return name; }
}
public string Score
{
get { return score; }
}
public override string ToString()
{
return String.Format("姓名:{0},分數:{1}", name, score);
}
}
運轉成果以下圖所示:

因而可知,我們沒法修正Student的個中某一個成員,只能經由過程結構函數創立一個新對象,知足"對象的原子性"。
並且也沒法修正Student對象實例的某個屬性值,相符"對象的常量性"。
3.假如有援用類型字段和屬性,若何做到"弗成變性"?
class Program
{
static void Main(string[] args)
{
string[] classes = {"語文", "數學"};
Student student = new Student("張三", "85", classes);
Console.WriteLine("==修正之前==");
Console.WriteLine(student.ToString());
string[] tempArray = student.Classes;
tempArray[0] = "英語";
Console.WriteLine("==修正以後==");
Console.WriteLine(student.ToString());
Console.ReadKey();
}
}
public struct Student
{
private readonly string name;
private readonly string score;
private readonly string[] classes;
public Student(string name, string score, string[] classes)
{
this.name = name;
this.score = score;
this.classes = classes;
}
public string Name
{
get { return name; }
}
public string Score
{
get { return score; }
}
public string[] Classes
{
get { return classes; }
}
public override string ToString()
{
string temp = string.Empty;
foreach (string item in classes)
{
temp += item + ",";
}
return String.Format("姓名:{0},總分:{1},加入的課程有:{2}", name, score,temp.Substring(0, temp.Length -1));
}
}
成果以下圖所示:

因而可知,照樣可以對對象的屬性直接修正賦值,不知足弗成變類型的"常量性"特色。
4.經由過程在結構函數和屬性的get拜訪器中復制的方法來知足弗成變性
class Program
{
static void Main(string[] args)
{
string[] classes = {"語文", "數學"};
Student student = new Student("張三", "85", classes);
Console.WriteLine("==修正之前==");
Console.WriteLine(student.ToString());
string[] tempArray = student.Classes;
tempArray[0] = "英語";
Console.WriteLine("==修正以後==");
Console.WriteLine(student.ToString());
Console.ReadKey();
}
}
public struct Student
{
private readonly string name;
private readonly string score;
private readonly string[] classes;
public Student(string name, string score, string[] classes)
{
this.name = name;
this.score = score;
this.classes = new string[classes.Length];
classes.CopyTo(this.classes, 0);
CheckScore(score);
}
public string Name
{
get { return name; }
}
public string Score
{
get { return score; }
}
public string[] Classes
{
get
{
string[] result = new string[classes.Length];
classes.CopyTo(result,0);
return result;
}
}
//檢測分數能否是2位數整數
private void CheckScore(string value)
{
string pattern = @"\d{2}";
if (!Regex.IsMatch(value, pattern))
{
throw new Exception("不是有用分數!");
}
}
public override string ToString()
{
string temp = string.Empty;
foreach (string item in classes)
{
temp += item + ",";
}
return String.Format("姓名:{0},總分:{1},加入的課程有:{2}", name, score,temp.Substring(0, temp.Length -1));
}
}
運轉成果以下圖所示:

另外,假如讓分數不知足前提,Student student = new Student("張三", "8", classes),就會報錯:
