C#基礎操作符詳解(上)


本節內容:

1.操作符概覽;

2.操作符的本質;

3.操作符與運算順序

4.操作符詳解。

 

1.操作符概覽:

 

 

 

操作符(Operator)也譯為”運算符”

操作符是用來操作數據的,被操作符操作的數據稱為操作數(Operand

表格從上往下優先級遞減,同一行運算符的優先級一樣一般按從左到右算,

“=”賦值操作符,是先運算右邊的值再運算左邊的值,所以是最后運算的。

 

2.操作符的本質

①操作符的本質是函數(即算法)的”簡記法”

假如沒有發明”+”只有Add函數,算式3+4+5將可以寫成AddAdd3,4),5

假設沒有發明”*”只有Mul函數,那么算式3+4*5將只能寫成Add3Mul4,5))

可見有操作符可讀性更強。

②操作符不能脫離與它關聯的數據類型(比如double數據類型的除法與int類型的除法相同數據結果不同)

可以說操作符就是與固定數據相關聯的一套基本算法的簡記法。

示例:為自定義的數據類型創建操作符。(格式為把方法名字改為”operator  想要定義的操作符”如:”operator +”)如下例子進一步說明了C#里面的操作符就是方法,也就是函數的一個簡記法。

 

    class Person
    {
        public string Name;
        //public static List<Person>GetMary(Person p1, Person p2)(一般方法自定義操作符之前)
        public static List<Person>operator +(Person p1, Person p2)
        {
            List<Person> people = new List<Person>();
            people.Add(p1);
            people.Add(p2);
            for (int i = 0; i < 11; i++)
            {
                Person child = new Person();
                child.Name = p1.Name + "&" + p2.Name + "'s child";
                people.Add(child);
            }
            return people;
        }
    }

 

 

 

 

3.操作符與運算順序

①操作符的優先級

可以使用圓括號提高被括起來的表達式的優先級。

圓括號可以嵌套。

不像數學里面有方括號和花括號,在C#語法中”[]”與”{}”有專門的用途。

②同優先級操作符的運算順序

除了帶有賦值功能的操作符,同優先級操作符都是有左到右進行運算,

帶有賦值功能的操作符的運算順序是由右到左(比如賦值運算符”=”),

與數學運算不同,計算機語言的同優先級運算沒有”結合率”:

3+4+5只能理解為Add(Add(3,4),5)不能理解為Add(3,Add(4,5)

 

  1. 操作符詳解

4.1基本操作符

①(成員訪問操作符)”.”操作符(上表中寫為X.Y):四種功能;

*訪問命名空間當中的子集命名空間;

*訪問名稱空間當中的類型;

*訪問類型的靜態成員(靜態成員隸屬於類本身故用類可以訪問,而用類的對象不能訪問類的靜態成員);

*訪問對象的成員(包括數據成員和方法);

②方法調用操作符”()”即方法后面跟着的那對圓括號(上表寫為f(x))。

調用方法一定要加圓括號,但是:

Action myAction = new Action(c.PrintHello);//PrintHello方法交給委托對象myAction管理

  myAction();//這樣在委托對象后面加個圓括號就相當於調用了被它管理的方法了,

這個時候PrintHello方法可以不帶圓括號。

③元素訪問操作符”[]”

   int[] myIntArray = new int[13];//創建int數組的實例13個元素

   int[] myIntArray2 = new int[]{1,2,3,4,5};//也可以在后面加花括號輸入相應值,這對或括號叫做"初始化器"[]里不寫數組大小會根據初始化器自動賦值...

   myIntArray[0]=2;//訪問的是第一個數組元素,訪問數組元素,[]里寫的是偏移量0開始

 

Dictionary<string, Student> stuDic = new Dictionary<string, Student>();//一個類名后面,跟着一個尖括號表示這個類是泛型

            //泛型是不完整的類如Dictionary<string, Student>在尖括號里要說明索引的類型(string)與值的類型(Student(順帶一提Dictionary是一個字典類型)

 

*總結元素訪問操作符”[]”里面放的是索引里面不一定是整數,如以下舉例。

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             Dictionary<string, Student> stuDic = new Dictionary<string, Student>();//一個類名后面,跟着一個尖括號表示這個類是泛型
 6             //泛型是不完整的類如Dictionary<string, Student>在尖括號里要說明索引的類型(string)與值的類型(Student)(順帶一提Dictionary是一個字典類型)
 7             for (int i = 1; i < 100; i++)
 8             {
 9                 Student stu = new Student();
10                 stu.Name = "s_" + i.ToString();
11                 stu.Score = 100+i;
12                 stuDic.Add(stu.Name, stu);//把stu放進字典里面,所以為stu.Name,值為stu
13             }
14             Student number6 = stuDic["s_6"];//說明了[]里不一定是整數,而一定是索引
15             Console.WriteLine(number6.Score);
16         }
17     }
18     class Student
19     {
20         public string Name;
21         public int Score;
22     }

 

x--x++:叫做后置的加加和后置的減減:

Int x=100; int y=x++;結果為x=101y=100;因為x++是先賦值再進行自增;

--x++x:叫做前置的加加和前置的減減:先進行自增或自減后進行賦值。

 

typeof()操作符和default()操作符

*typeof操作符的作用為查看變量的種類:

Type t = typeof(int);

            Console.WriteLine(t.Namespace);

            Console.WriteLine(t.FullName);

            Console.WriteLine(t.Name);

*Default操作符使操作數取默認值:數值型為0,引用型為null

  int x=default(int);//default操作的類型為結構體類型即數值類型時就返回內存塊當中為0的值

  Console.WriteLine(x);

輸出為0

  Form myForm = default(Form);//default操作的類型為引用類型時就返回內存塊當中為0的值即為null

  Console.WriteLine(myForm==null);

輸出為true

當為枚舉型enum時: Level level=default(Level);

             Console.WriteLine(level);

  enum Level

    {

        Mid,

        Low,

        High

}

結果為Mid,如果把Mid的位置和Low互換則結果為Low,這是因為當default操作符遇到枚舉類型會把它當做數值型來處理,即第一個元素為0,后面的依次+1

如果這樣寫:

enum Level

    {

        Mid=1,

        Low=0,

        High=2

}則返回值為Low。當用default獲取枚舉值的時候要小心,如果這樣寫:

enum Level

    {

        Mid=1,

        Low=3,

        High=2

}返回值為0,出錯了,所以在設置枚舉值時最好給元素一個0的整數值。

 

先說明:關鍵字var:幫助生成隱式類型變量:

 int x;//顯式變量,明確的告訴了編譯器x屬於什么數據類型

         var y;//隱式變量,告訴編譯器y的類型暫時不知道,當我賦值的時候看着辦

C#是強類型語言變量一旦確定數據類型就不可以變更。

new操作符:

*幫助我們在內存當中創建一個類型的實例並且立刻調用這個實例的實例構造器(所謂的構造函數),並取得的實例地址....

  new Form();//調用默認實例構造器

創建這個實例之后如果沒有任何變量去引用它,訪問它,過一會垃圾收集就把這個實例所占用的堆內存當做垃圾給收回來了。

*除了創建實例和調用實例構造器之外還能把new取得的實例地址通過賦值符號交給負責訪問這個實例的變量。這樣就在變量和實例之間構成了引用關系。有了這個引用關系之后就可以通過這個變量來訪問實例。如: Form myForm=new Form();//調用默認實例構造器

  myForm.Text = "Hello!";//通過變量來訪問實例

 

*上面為主要功能,以下為附加功能:調用實例的初始化器:

  Form myForm = new Form() {Text="Hello!" };在實例后面加花括號里面加屬性的值。

可以初始化多個屬性,中間逗號隔開。

還有:有的時候用實例只是一次性的沒必要創建一個引用變量去初始化它,可以采用這時初始化器就發揮作用了:new Form(){Text=”Hello!”}.ShowDialog();只是由於沒有引用變量引用(沒有小孩牽着這個氣球,氣球一會就飛走了)所以一段時間后,垃圾回收器把它的堆內存回收。

a、錯覺:要創建類的實例就一定要使用new操作符,錯誤的。如string Name = "Hello!";

String是一個類,創建實例時不用new操作符,這種方式叫做C#”語法糖衣”,原因為為了統一使stringint的書寫格式,而把string類的new操作符隱藏起來了,string可以用new但平常不這么用。類似的還有數組:

new操作符:

int[] myArray = new int[10];//由於int的實例構造器有點特殊不用圓括號調用;

不用new操作符時:

 int[] myArray = { 1,2,3,4};

b、new操作符特殊用法:為匿名類型創建實例,

Form myForm=new Form(){Text=”Hello!”};當為非匿名類型創建實例時new后面要加類型名,

當為匿名類型創建實例時:如:

Var person=new {Name=”Mr li”,Age=34};//new操作符后面不跟類型,直接用初始化器初始化實例,什么類型?讓編譯器根據初始化內容自行判斷,不過該實例一定要有引用變量引用,不知道類型?用var隱式變量即可。那到底是什么類型呢?

Console.WriteLine(Person.GetType().Name);

輸出為:<>f__AnonymousType0`2

“<>f__AnonymousType”為約定的前綴,0表示我在程序中創建的第一個,’2表示這個類型為泛型類,構成這個類型的時候你需要兩個類型來構成它,哪兩個類型呢?就是初始化器里面的一個是string,一個是int。這是在創建匿名類型時編譯器自己識別的類型。

這里才真正體現出var類型(全部)功能的強大之處與重要性。因為如上一種情況就算你想寫出它的類型也不知道叫什么名字。

*記住new操作符與var隱式變量組合的使用方法:是為匿名對象創建對象並且用隱式類型變量來引用這個實例。

c、new操作符有危險性(功能強大伴隨的濫用風險)一旦在某個類里面(比如main函數隸屬的Program類)用new操作符創建了某個類的實例(比如在main函數中創建Form類),那么這個類(Form)就與主類(Program)緊緊耦合在一起,Pragram類就緊緊依賴於Form類,一旦某個類(Form)出現問題,整個耦合體都無法正常運行。即new操作符會造成緊耦合。那怎么解決?在軟件工程有項非常重要和實用的技術叫做”設計模式”,在”設計模式”當中有一種非常重要的模式叫做”依賴注入”dependenty injection),該模式就是幫助我們把緊耦合變成相對松的耦合。有概念即可:new操作符有風險慎用,大型程序中為了避免有緊耦合的情況我們有一種叫做”依賴注入”的設計模式可以使用,實現不必關注。

*程序設計追求”高內聚低耦合”

d、new關鍵字的多用性(不是操作符而是關鍵字):如

class Student

    {

        public void Report()

        {

            Console.WriteLine("I'm a student");

        }

    }

    class CsStudent:Student

    {

        new public void Report()//這叫子類對父類方法的隱藏,這里的new便不是操作符而是修飾符用來修飾new后面的方法的。(並不常見)

        {

            Console.WriteLine("I'm a Cstudent");

        }

}

Student stu = new Student();

            stu.Report();

            CsStudent csStu = new CsStudent();

            csStu.Report();時分別調用各自的Report()方法。

 

⑦checked()unchecked()操作符:用來檢查()內的值在內存中是否有溢出:(Overflow)

C#是強類型語言,任何一個變量它在內存里面都有數據類型,而數據類型有個非常重要的作用就是表示這種數據類型的實例在內存當中能夠占多大的空間,一個值在內存空間所占的大小決定了這個值能夠表達的范圍,一旦超出這個范圍這個值就產生了溢出。Checked就是告訴我們要去檢出溢出,unchecked則告訴我們不用:

 uint x = uint.MaxValue;

            Console.WriteLine(x);

            string binStr = Convert.ToString(x, 2);

            Console.WriteLine(binStr);

            try

            {

                uint y = checked(x + 1);//檢測x+1是否溢出,溢出后去catch捕獲異常

                Console.WriteLine(y);

            }

            catch (OverflowException ex)

            {

                Console.WriteLine("There is overflow");

            }

Unchecked()操作符表示不用檢查,C#中默認該種方式。Checked也有其他用法:

Checked

{

  try

            {

                uint y = checked(x + 1);//檢測x+1是否溢出,溢出后去catch捕獲異常

                Console.WriteLine(y);

            }

            catch (OverflowException ex)

            {

                Console.WriteLine("There is overflow");

            }

}

直接判斷整個語句塊中所有語句是否有溢出。

 

delegate操作符(關鍵字)最主要的作用為聲明一種叫委托的數據類型,委托是C#非常重要的概念。本節主要講其作為操作符的作用(非常稀有因為拉姆達表達式(Lambda Expressions)的出現就是來替代delegate當做操作符的場景):使用delegate生成匿名方法:

 this.myButton.Click +=delegate (object sender, RoutedEventArgs e)//使用delegate聲明了一個匿名方法

        {

            this.myTextBox.Text = "Hello World!";

        };

程序原本應為:this.myButton.Click += myButton_Click;

 void myButton_Click(object sender, RoutedEventArgs e)

        {

            this.myTextBox.Text = "Hello World!";

        }

現在替代這用用法的拉姆達表達式:

 this.myButton.Click += (sender,  e)=>

        {

            this.myTextBox.Text = "Hello World!";

        };

語法的演變可見C#語法越來越簡潔,功能越來越強大。

 

sizeof()操作符:

a、只能獲取結構體類型在內存中所占字節數,默認情況下:sizeof只能去獲取基本數據類型他們的實例在內存當中所占的字節數,基本數據類型:比如intuint...說白了就是C#關鍵字里面那些除了stringobject的數據類型:因為這兩個為引用類。

b、在非默認的情況下可以使用sizeof去獲取自定義的結構體類型的實例它在內存中占的字節數,但是需要把它放在不安全的上下文當中:

  unsafe

   {

    int x=sizeof(Student);

   }

Decimal數據類型精確度比double高占16個字節;

⑩最后一個”基本操作符”:”->”

*類(class)屬於引用類型,結構體(struct)屬於值類型。C#中有嚴格的規定像指針操作,取地址操作,用指針去訪問成員的操作,只能用來操作結構體類型,不能用它們去操作引用體類型。(Class

要運行不安全代碼除了要把它放在unsafe{}里面,還要再項目->最后一項(相應項目屬性)->生成->勾選”允許生成不安全代碼”,所謂雙重保險。

使用該操作符時要在unsafe情況下使用:

unsafe

            {

                Student stu;

                stu.ID = 1;

                stu.Score = 99;

                Student*pStu=&stu;

                pStu->Score = 100;

                Console.WriteLine(stu.Score);

            }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM