- C#由微軟開發(fā)舟误,并由ECMA和ISO核準(zhǔn)認(rèn)可石挂。
- C#由Anders Hejlsberg和他的團隊在.NET框架期間開發(fā)的
- C#專為公共語言基礎(chǔ)結(jié)構(gòu)(CLI)設(shè)計的竿裂,CLI由可執(zhí)行代碼和運行時環(huán)境組成矩父,允許在不同計算機平臺和體系結(jié)構(gòu)上使用各種高級語言没龙。
- 集成開發(fā)環(huán)境IDE:編輯=>編譯=>調(diào)試=>發(fā)布
- 學(xué)習(xí)路徑:語言=>類庫=>框架
功能
- C#的構(gòu)想接近于C和C++奢赂,是一門面向?qū)ο蟮木幊陶Z言唱遭,并與Java非常相似。
- .NET 指 .Net Framework框架 是一種平臺呈驶、技術(shù)
- C# 可以開發(fā)基于.Net平臺的應(yīng)用
.Net開發(fā)領(lǐng)域
- 桌面應(yīng)用程序 WinForm
- Internet應(yīng)用程序 WebService/ASP.NET
- 手機開發(fā) WP7
網(wǎng)絡(luò)架構(gòu)模式
- B/S
瀏覽器(Browser)/服務(wù)器(Server)模式 - C/S
客戶端(Client)/服務(wù)端(Server)模式
桌面開發(fā)(WinForm)的網(wǎng)絡(luò)應(yīng)用程序拷泽,如飛秋恩沽、QQ等
環(huán)境
C#是.NET框架的一部分底扳,且用于編寫.NET應(yīng)用程序奏赘。
.NET框架是一個創(chuàng)新的平臺腿堤,能編寫Windows應(yīng)用程序琼懊、Web應(yīng)用程序姐帚、Web服務(wù)旦部。.NET由一個巨大的代碼庫組成在扰,用于C#等客戶端語言霉晕。
路線
入門
# 編寫源代碼
$ vim app.cs
// using關(guān)鍵字用于在程序中包含System命名空間
using System;
// 命名空間聲明
namespace Application
{
// 類聲明:程序的最小單元
class Klass
{
// 入口點方法:主函數(shù)
static void Main(string[] args)
{
// 在屏幕上顯示消息庭再,WriteLine是定義在System命名空間下Consolle類的方法
Console.WriteLine("Hello World");//命令:以分號結(jié)束
// 針對VS.NET,程序會等待一個按鍵動作牺堰,防止程序從VS.NET啟動時屏幕會快速運行并關(guān)閉拄轻。
Console.ReadKey();
//F5調(diào)試運行 Ctrl+F5不調(diào)試直接運行
}
}
}
# 編譯源代碼
$ csc app.cs
Microsoft (R) Visual C# Compiler version 4.7.3056.0
for C# 5
Copyright (C) Microsoft Corporation. All rights reserved.
This compiler is provided as part of the Microsoft (R) .NET Framework, but only supports language versions up to C# 5, which is no longer the latest version. For compilers that support newer versions of the C# programming language, see http://go.microsoft.com/fwlink/?LinkID=533240
# 生成可執(zhí)行文件
$ ls
app.cs app.exe
# 執(zhí)行程序
$ app.exe
Hello World
代碼剖析
- 類class是構(gòu)成程序的主體
- 命名空間namespace以樹型結(jié)構(gòu)組織類
- C#是大小寫敏感的
- 語句和表達(dá)式以分號結(jié)尾
- 程序的執(zhí)行從Main()方法開始
- 與Java不同的是,文件名可以不同于類名伟葫。
類庫的引用
- DLL引用 黑盒引用
- 項目引用 白盒引用
語法
$ vim rect.cs
using System;
namespace RectangleApp
{
class Rectangle
{
double length;
double width;
public void AcceptDetails()
{
length = 1.5;
width = 3;
}
public double GetArea()
{
return length * width;
}
public void Display()
{
Console.WriteLine("Length:{0}", length);
Console.WriteLine("Width:{0}", width);
Console.WriteLine("Area:{0}", GetArea());
}
}
class ExecuteRectangle
{
static void Main(string[] args)
{
Rectangle rect = new Rectangle();
rect.AcceptDetails();
rect.Display();
Console.ReadLine();
}
}
}
$ csc rect.cs
$ rect.exe
Length:1.5
Width:3
Area:4.5
從程序中輸出文本
Console.WriteLine(格式字符串(含替代標(biāo)記)恨搓, 替換值0, 替換值1...)
System
命名空間中的Console
類提供ReadLine()
函數(shù),用于接收來自用戶的輸入,并將其存儲到一個變量中斧抱。
int num;
num = Convert.ToInt32(Console.ReadLine());
標(biāo)識符
用于識別類常拓、變量、函數(shù)或任何其它用戶定義的項目辉浦。
- 標(biāo)識符必須以字母弄抬、下劃線、@開頭宪郊,后跟字母掂恕、數(shù)字、下劃線废膘、@。
- 標(biāo)識符第一個字符不能是數(shù)字
- 標(biāo)識符必須不包含任何嵌入的空格或符號
- 標(biāo)識符不能是C#關(guān)鍵字慕蔚,除非有@前綴丐黄。
- 標(biāo)識符必須區(qū)分大小寫
- 不能與C#類庫名稱相同
- @字符只能放在標(biāo)識符首位,不推薦將@作為常用字符孔飒。
關(guān)鍵字
關(guān)鍵字是C#編譯器預(yù)定義的保留字灌闺,不能作為標(biāo)識符。關(guān)鍵字分為保留關(guān)鍵字(Reserved Keywords) 和上下文關(guān)鍵字(Contextual Keywords)坏瞄。
- 上下文關(guān)鍵字是僅在特定的語言結(jié)構(gòu)中充當(dāng)關(guān)鍵字的標(biāo)識符
關(guān)鍵字約定
- 關(guān)鍵字全部由小寫字母組成
- 關(guān)鍵字不能用作變量名或任何其他形式的標(biāo)識符桂对,除非以@字符開始。
堆棧
程序運行時鸠匀,數(shù)據(jù)必須存儲在內(nèi)存中蕉斜。一個數(shù)據(jù)項需要多大內(nèi)存、存儲在什么地方缀棍、如何存儲都依賴于該數(shù)據(jù)項的類型宅此。運行中的程序使用兩個內(nèi)存區(qū)域來存儲數(shù)據(jù):棧和堆。
棧
棧是一個內(nèi)存數(shù)組爬范,是一個LIFO(Last-In First-Out父腕,后進(jìn)先出)的數(shù)據(jù)結(jié)構(gòu)。
棧存儲幾種類型的數(shù)據(jù)
- 某些類型變量的值
- 程序當(dāng)前的執(zhí)行環(huán)境
- 傳遞給方法的參數(shù)
棧的特征
- 數(shù)據(jù)只能從棧的頂端插入和刪除
- 把數(shù)據(jù)放到棧頂成為入棧(push)
- 從棧頂刪除數(shù)據(jù)成為出棧(pop)
堆
堆是一塊內(nèi)存區(qū)域青瀑,在堆里可以分配大塊的內(nèi)存用于存儲某類型的數(shù)據(jù)對象璧亮。與棧不同,堆里的內(nèi)存能夠以任意順序存入和移除斥难。
程序可在堆中存儲數(shù)據(jù)枝嘶,但并不能顯式地刪除。CLR的自動GC(Garbage Collector哑诊,垃圾收集器)在判斷出程序的代碼將不會再訪問某數(shù)據(jù)項時躬络,自動清除無主的堆對象。
類型
- C程序是一組函數(shù)和數(shù)據(jù)類型
- C++程序是一組函數(shù)和類
- C#程序是一組類型聲明
C# 程序是一組類型聲明
- C#程序或DLL的源代碼是一組一種或多種類型聲明
- 對于可執(zhí)行程序搭儒,類型聲明中必須有一個包含Main方法的類穷当。
- 命名空間是一種把相關(guān)的類型聲明分組并命名的方法
C# 程序是一組類型聲明提茁,學(xué)習(xí)C#就是學(xué)習(xí)如何創(chuàng)建和使用類型。什么是類型呢馁菜,可將它想象成一個用來創(chuàng)建數(shù)據(jù)結(jié)構(gòu)的模板茴扁。模板本身并不是數(shù)據(jù)結(jié)構(gòu),但它詳細(xì)說明了由該模板構(gòu)造的對象的特性汪疮。
類型的組成元素
- 名稱
- 用來保存數(shù)據(jù)成員的數(shù)據(jù)結(jié)構(gòu)
- 行為和約束條件
實例化類型
從某個類型模板創(chuàng)建實際的對象峭火,稱為實例化該類型。
- 通過實例化類型而創(chuàng)建的對象被稱為類型的對象或?qū)嵗?/li>
- C#程序中智嚷,每個數(shù)據(jù)項都是某種類型的實例卖丸。
預(yù)定義類型
數(shù)據(jù)項的類型定義了存儲數(shù)據(jù)需要的內(nèi)存大小與組成該類型的數(shù)據(jù)成員。類型還決定了對象在內(nèi)存中的存儲位置 - 堆或棧盏道。
類型被分為兩種:值類型和引用類型稍浆,兩種類型的對象在內(nèi)存中的存儲方式不同。
- 值類型
Value types
僅需一段單獨的內(nèi)存猜嘱,用于存儲實際的數(shù)據(jù)衅枫。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
// 命名空間
namespace ConsoleApp
{
//枚舉類型需放在類class之外,才能被其它類調(diào)用
//枚舉類型:限定變量的可能值朗伶,其對應(yīng)的是整型數(shù)值弦撩,默認(rèn)從0開始。
enum Weekday { Monday, Tuesday, Wenesday }
//枚舉類型:可定義帶數(shù)字的枚舉類型
enum Color {Red = 1, Blue = 2, Green = 3};
//類:程序的最小單元
class Program
{
//struct和enum均為值類型论皆,存儲在內(nèi)存的棧上益楼。
//結(jié)構(gòu)體
struct Person
{
public int age;
public string name;
public string firstName;
public string lastName;
}
//程序入口:主函數(shù)
static void Main(string[] args)
{
//所有類型均繼承自 System.Object
object obj = null;
//值類型 繼承自 System.ValueType
int i1 = 0;
System.Int32 i2 = 10;
//變量小寫,必須預(yù)先聲明類型
bool flag = true;
float f = 1.23f;
//變量轉(zhuǎn)換
string str = "hello";
//short s = (short)str;
//string str1 = Convert.ToString(f);
//調(diào)用結(jié)構(gòu)
Person person = new Person();
person.age = 20;
person.name = "junchow";
//使用枚舉
var day = Weekday.Tuesday;
Console.WriteLine(Weekday.Monday);
Console.ReadLine();
}
}
}
- 引用類型
Reference types
需要兩段內(nèi)存点晴,第一段存儲實際的數(shù)據(jù)偏形,位于堆中。第二段是一個引用觉鼻,指向數(shù)據(jù)在堆中的存放位置俊扭。
- 指針類型
Pointer types
指針類型存儲另一種類型的內(nèi)存地址,C#的指針與C或C++中的指針有相同的功能坠陈。
// 聲明指針類型
type* identifier;
// 例如
char* cptr;
int * iptr;
C#中沒有全局變量的概念萨惑,所有的變量必須由該類的實例進(jìn)行操作,這樣做提升了安全性仇矾,但某些情況下卻顯得力不從心庸蔼。因此,在保存類的公共信息時贮匕,會使用靜態(tài)變量姐仅。
# 在變量前添加static關(guān)鍵字即可聲明為靜態(tài)變量
static <data_type> <variable_name> = value;
值類型
值類型變量可直接分配給一個值,從System.ValueType
中派生,最終繼承自System.Object
掏膏,值類型直接包含數(shù)據(jù)劳翰。
$ vim size.cs
using System;
namespace DatatypeApp
{
class App
{
static void Main(string[] args)
{
Console.WriteLine("Size of bool:{0}", sizeof(bool));
Console.WriteLine("Size of byte:{0}", sizeof(byte));
Console.WriteLine("Size of char:{0}", sizeof(char));
Console.WriteLine("Size of decimal:{0}", sizeof(decimal));
Console.WriteLine("Size of double:{0}", sizeof(double));
Console.WriteLine("Size of float:{0}", sizeof(float));
Console.WriteLine("Size of int:{0}", sizeof(int));
Console.WriteLine("Size of long:{0}", sizeof(long));
Console.WriteLine("Size of sbyte:{0}", sizeof(sbyte));
Console.WriteLine("Size of short:{0}", sizeof(short));
Console.WriteLine("Size of uint:{0}", sizeof(uint));
Console.WriteLine("Size of ulong:{0}", sizeof(ulong));
Console.WriteLine("Size of ushort:{0}", sizeof(ushort));
Console.ReadLine();
}
}
}
$ csc size.cs
$ size.exe
Size of bool:1
Size of byte:1
Size of char:2
Size of decimal:16
Size of double:8
Size of float:4
Size of int:4
Size of long:8
Size of sbyte:1
Size of short:2
Size of uint:4
Size of ulong:8
Size of ushort:2
如需得到一個類型或一個變量在特定平臺上的準(zhǔn)確尺寸,可使用sizeof()
馒疹。表達(dá)式sizeof(type)
產(chǎn)生以字節(jié)為單位存儲對象或類型的存儲尺寸佳簸。
引用類型
引用類型不包含存儲在變量中的實際數(shù)據(jù),包含的是對變量的引用颖变。它們指向的是一個內(nèi)存位置生均。使用多個變量時,引用類型可指向一個內(nèi)存位置腥刹。若內(nèi)存位置的數(shù)據(jù)是由一個變量改變的马胧,其他變量會自動反映這種值的變化。內(nèi)置的引用類型有object衔峰、dynamic佩脊、string。
C#內(nèi)置引用類型分為object
朽色、string
邻吞、dynamic
對象類型
對象類型是C#通用類型系統(tǒng)(Common Type System - CTS)中所有數(shù)據(jù)類型的終極基類组题。Object是System.Object類的別名葫男。所以對象類型可以被分配任何其他類型的值。在分配之前崔列,需先進(jìn)行類型轉(zhuǎn)換梢褐。
Object終極基類,是CLR運行時定義的最基礎(chǔ)的類型赵讯,CLR運行時要求所有類型盈咳,不管是系統(tǒng)定義的類型,還是自定義的類型边翼,都必須從Object類派生鱼响。
注意:一個值類型轉(zhuǎn)換為對象類型時被稱為裝箱,但一個對象類型被轉(zhuǎn)換為值類型時被稱為拆箱组底。
由于所有類型都從System.Object
類型派生而來丈积,所以每個類型的每個對象實例均有一組最基本的方法。
- Equals 虛方法债鸡,若兩個對象具有相同的值江滨,則返回 true。
[__DynamicallyInvokable]
public virtual bool Equals(object obj)
{
return RuntimeHelpers.Equals(this, obj);
}
- ToString 虛方法厌均,默認(rèn)返回類型的完整名稱
this.GetType().FullName
- GetHashCode 虛方法唬滑,返回對象值得哈希值
- GetType
返回從Type派生的一個類型的實例,指出調(diào)用GetType的對象是什么類型,返回的Type對象和反射類配合晶密,可獲取對象類型相關(guān)元數(shù)據(jù)信息擒悬。
GetType并非虛方法,目的是防止類重寫該方法惹挟,隱瞞其類型以破壞類型的安全性茄螃。
object obj1 = new object();//小寫objecct是System.Object類的別名
object obj2 = new Object();
Console.WriteLine(obj1.GetType());//System.Object
Console.WriteLine(obj1.ToString());//System.Object
Console.ReadLine();
字符串類型
字符串類型運行為變量分配任何字符串值,字符串類型string
是System.String
類的別名连锯,它是從對象類型object
派生的归苍。字符串類型的值可通過兩種形式分配:引號和@
引號。
String str = "hi"
@"hi"
C#的字符串類型前可添加@
(稱作“逐字字符串”)將轉(zhuǎn)義字符\
當(dāng)作普通字符對待运怖。
string str = @"C:\Windows";
string str = "C:\\Windows";
@
字符串中可任意換行拼弃,換行符、縮進(jìn)空格都計算在字符串長度之內(nèi)摇展。
C#中字符串一旦創(chuàng)建就不可以更改長度大小吻氧,每次使用System.String
類中方法時,都要在內(nèi)存中創(chuàng)建新的字符串對象咏连,也就是說每次都要為新對象分配空間盯孙。在需要對字符串執(zhí)行重復(fù)修改的情況下,與創(chuàng)建新的String
對象相關(guān)的系統(tǒng)開銷可能會非常昂貴祟滴。
//分配固定內(nèi)存大小
string controllername = "User";
//創(chuàng)建新的內(nèi)存分配給controllername振惰,代價昂貴。
controllername += "Controller";
如果要修改字符串而非創(chuàng)建新的對象則可使用System.Text.StringBuilder
類垄懂,例如:當(dāng)在一個循環(huán)中將許多字符串連接起來時骑晶,此時可提升性能。
//指定分配大小草慧,當(dāng)指定分配大小后性能會提升桶蛔。
StringBuilder sb = new StringBuilder(20);
//分配到堆區(qū)
sb.Append("User");
//不會被銷毀直接追加
sb.Append("Controller");
String聲明后在內(nèi)存中大小是不可以修改的,使用StringBuilder則可自由擴展大小漫谷,原因String分配在棧區(qū)仔雷,StringBuilder則分配在堆區(qū)。
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
Stopwatch timer = new Stopwatch();
timer.Start();
//string str = string.Empty;
//for(int i=0; i<100000; i++)
//{
// str += i.ToString(); //elapsed milliseconds : 16563
//}
StringBuilder sb = new StringBuilder();
for(int i=0; i<100000; i++)
{
sb.Append(i.ToString());//elapsed milliseconds : 14
}
timer.Stop();
Console.WriteLine("elapsed milliseconds : {0}", timer.ElapsedMilliseconds);
Console.ReadLine();
}
}
}
用戶定義類型
- 類類型 class
- 結(jié)構(gòu)類型 struct
- 數(shù)組類型 array
- 枚舉類型 enum
- 委托類型 delegate
- 接口類型 interface
類型通過類型聲明創(chuàng)建
- 要創(chuàng)建的類型的種類
- 新類型的名稱
- 對類型中每個成員的聲明(名稱和規(guī)格)
動態(tài)類型
動態(tài)類型可存儲任何類型的值在動態(tài)數(shù)據(jù)類型變量中舔示,這些變量的類型檢查時在運行時發(fā)生的碟婆。
# 聲明動態(tài)類型
dynamic <variable_name> = value;
# 例如
dynamic variable = 20;
動態(tài)類型與對象類型相似,對象類型變量的類型檢查時在編譯時發(fā)生的斩郎,動態(tài)類型變量的類型檢查時在運行時發(fā)生的脑融。
靜態(tài)類型
每個變量都包括變量類型,編譯器可以確定運行時需要的內(nèi)存容量以及那些部分應(yīng)該存放在棧上缩宜,哪些部分應(yīng)該存放在堆上肘迎。變量的類型在編譯時確定甥温,并且不能再運行時修改,這叫靜態(tài)類型妓布。
可空類型
某些情況下姻蚓,特別是使用數(shù)據(jù)庫時,希望表示變量目前未保存有效的值匣沼。對于引用類型很簡單狰挡,可見變量設(shè)置為null
。但定義值類型的變量時释涛,不管它的內(nèi)容是否有效加叁,內(nèi)存都會進(jìn)行分配。
對于這種情況唇撬,可能會使用一個布爾指示器來和變量關(guān)聯(lián)它匕,如果值有效則設(shè)置為true
否則設(shè)置為false
。
可空類型運行創(chuàng)建可以標(biāo)記為有效或無效的值類型窖认,在使用之前確定值得有效性豫柬。普通的值類型成為非可空類型。
using System;
namespace NullApp
{
class Nullable
{
static void Main(string[] args)
{
// ?單問號
// 用于對int扑浸、double烧给、bool等無法直接賦值為null的數(shù)據(jù)進(jìn)行null的賦值。
int? n = 1;
// 意思是此數(shù)據(jù)是Nullable可空類型的
Nullable<int> m = new Nullable<int>(1);
Console.WriteLine("n = {0}, m = {1}", n, m);
// 可空類型
// C#提供了一個特殊的數(shù)據(jù)類型nullable可空類型
// 可空類型可以表示其基礎(chǔ)值類型正常范圍內(nèi)的值喝噪,再加上一個null值础嫡。
// 在處理數(shù)據(jù)庫和其他包含可能未賦值的元素的數(shù)據(jù)類型時
// 將null復(fù)制給數(shù)值類型或布爾類型的功能特別有用
int? i = null;
int? j = 1;
double? x = new double?();
double? y = 3.14;
// 數(shù)據(jù)庫中的布爾型字段可存儲值true或false或者該字段也可以未定義
bool? flag = new bool?();
Console.WriteLine("i={0}, j={1}, x={2}, y={3}, flag={4}", i, j, x, y, flag);
// Null合并運算符??
// Null合并運算符用于定義可空類型和引用類型的默認(rèn)值
double? a = null;
Console.WriteLine("a = {0}", a ?? 1.1);
// Null合并運算符為類型轉(zhuǎn)換定義了一個預(yù)設(shè)值,以防止可能類型的值Null仙逻。
// Null合并運算符把操作數(shù)類型隱式轉(zhuǎn)換為另一個可空或非空的值類型的操作數(shù)的類型
// 如果第一個操作數(shù)的值為空驰吓,則運算符返回第二個操作數(shù)的值涧尿,否則返回第一個操作數(shù)的值系奉。
double? b = 1.23;
Console.WriteLine("b = {0}", b ?? 3.21);
Console.ReadLine();
}
}
}
類型轉(zhuǎn)換
類型轉(zhuǎn)換從根本上說是類型鑄造,或者說是把數(shù)據(jù)從一種類型轉(zhuǎn)換為另一種類型姑廉。
C#中缺亮,類型鑄造有兩種形式
- 隱式類型轉(zhuǎn)換
隱式類型轉(zhuǎn)換是C#默認(rèn)的以安全方式進(jìn)行的轉(zhuǎn)換,不會導(dǎo)致數(shù)據(jù)丟失桥言。例如萌踱,從小范圍的整形轉(zhuǎn)換為大范圍的整形,從派生類轉(zhuǎn)換為基類号阿。
int i = 1;
double d = 1.1;
int n = i + d;//錯誤:無法將類型double隱式地轉(zhuǎn)換為int
當(dāng)高精度數(shù)據(jù)類型與低精度數(shù)據(jù)類型進(jìn)行運算時并鸵,定義運算結(jié)果的變量類型必須與高精度的變量類型保持一致,以防止在運算過程中造成數(shù)據(jù)丟失扔涧。
- 顯式類型轉(zhuǎn)換
顯示類型轉(zhuǎn)換即強制類型轉(zhuǎn)換园担,顯示轉(zhuǎn)換需要強制轉(zhuǎn)換運算符届谈,且強制轉(zhuǎn)換會造成數(shù)據(jù)丟失。
$ vim conv.cs
using System;
namespace TypeConversionApp
{
class Explicit
{
static void Main(string[] args)
{
double d= 123.456;
int i;
i = (int)d;
Console.WriteLine("d={0}, i={1} ", d, i);
Console.ReadKey();
}
}
}
$ cs conv.cs
$ conv.exe
d=123.456, i=123
變量
- 變量是一個名稱弯汰,表示程序執(zhí)行時存儲在內(nèi)存中的數(shù)據(jù)艰山。
變量是一個供程序操作的存儲區(qū)的名字。C#中每個變量都有一個特定的類型咏闪,類型決定了變量的內(nèi)存大小和布局曙搬。范圍內(nèi)的值可存儲在內(nèi)存中,可對變量進(jìn)行一系列操作鸽嫂。
class Test
{
static void Main()
{
string username;
System.Console.Write("username: ");
username = System.Console.ReadLine();
System.Console.WriteLine("your username is {0}", username);
}
}
變量習(xí)慣采用駝峰法Camel命名纵装,即大小寫形式。
C#提供4種變量
- 本地變量
在方法的作用域內(nèi)保存的臨時變量据某,不是類型的成員搂擦。 - 字段
保存和類型或類型實例相關(guān)的數(shù)據(jù),是類型的成員哗脖。 - 參數(shù)
用于從一個方法到另一個方法傳遞數(shù)據(jù)的臨時變量瀑踢,不是類型的成員。 - 數(shù)組元素
同類數(shù)據(jù)項構(gòu)成的有序集合的一個成員才避,可以是本地變量橱夭,也可以是類型的成員。
# 變量定義
<data_type> <variable_list>;
# 示例
int i,j,k;
char c,ch;
float f;
double d;
# 變量定義時初始化
int n = 1;
變量聲明
變量使用前必須聲明桑逝,變量聲明定義了變量棘劣,并完成兩件事情。
- 給變量命名楞遏,并為它關(guān)聯(lián)一種類型茬暇。
- 讓編譯器為它分配一塊內(nèi)存
變量初始化(variable initializer)
除聲明變量的名稱和類型外,聲明還能將它的內(nèi)存初始化為一個明確的值寡喝。
# 變量通過在等號后跟一個常量表達(dá)式進(jìn)行初始化(賦值)
variable_name = value;
# 變量可在聲明時被初始化糙俗,即指定一個初始值。
<data_type> <variable_name> = value;
正確地初始化變量是一個良好的編程習(xí)慣预鬓,否則有時程序會產(chǎn)生意想不到的結(jié)果巧骚。
$ vim def.cs
using System;
namespace VariableDefinition
{
class Program{
static void Main(string[] args)
{
short s;
int i;
double d;
s = 1;
i = 10;
d = s + i;
Console.WriteLine("s = {0}, i = {1}, d = {2}", s, i, d);
Console.ReadLine();
}
}
}
$ csc def.cs
$ def.exe
s = 1, i = 10, d = 11
左值與右值
C#中的兩種表達(dá)式
-
lvalue
左值表達(dá)式可出現(xiàn)在賦值語句的左邊或右邊
變量是左值的,可出現(xiàn)在賦值語句的右邊格二。
int i = 10;
-
rvalue
右值表達(dá)式可出現(xiàn)在賦值語句的右邊劈彪,不能出現(xiàn)在賦值語句的左邊。
數(shù)值是右值的顶猜,因此不能被賦值沧奴,不能出現(xiàn)在賦值語句的左邊。
10 = 100;// 無效語句长窄,編譯時錯誤滔吠。
常量
類
- 類是一種活動的數(shù)據(jù)結(jié)構(gòu)
面向?qū)ο蠓治龊驮O(shè)計產(chǎn)生之前远寸,程序員把程序當(dāng)作指令的序列。焦點主要放在指令的組合和優(yōu)化上屠凶。隨著面向?qū)ο蟮某霈F(xiàn)驰后,焦點從優(yōu)化指令轉(zhuǎn)移到組織程序的數(shù)據(jù)和功能上。程序的數(shù)據(jù)和功能被組織為邏輯上相關(guān)的數(shù)據(jù)項和函數(shù)的封裝集合矗愧,并稱為類灶芝。
類是一個能存儲數(shù)據(jù)并執(zhí)行代碼的數(shù)據(jù)結(jié)構(gòu),包含數(shù)據(jù)成員和函數(shù)成員唉韭。
方法
var
關(guān)鍵字并不是特定類型變量的符號夜涕,只是句法上的速記,表示任何可以從初始化語句的右邊推斷出的類型属愤。C#中的var
不像JS的那樣可以引用不同類型女器,C#的var
是從等號右邊推斷出的實際類型的速記,它并不改變C#的強類型性質(zhì)住诸。
-
var
只能用于本地變量驾胆,不能用于字段。 -
var
只能在變量聲明中包含初始化時使用 - 一旦編譯器推斷出變量的類型贱呐,它就是固定且不能更改的丧诺。
using System;
namespace CalculorApp
{
class NumberManipulator
{
// 方法調(diào)用
public int Max(int i, int j)
{
return i>j ? i : j;
}
// 遞歸方法調(diào)用
// 一個方法可以自我調(diào)用,就是所謂的遞歸奄薇。
public int Factorial(int i)
{
if(i==1){
return 1;
}else{
return Factorial(i-1)*i;
}
}
// 按值傳遞參數(shù)
// 參數(shù)傳遞的默認(rèn)形式驳阎,但調(diào)用方法時會為每個值創(chuàng)建一個新的存儲位置。
// 實際參數(shù)的值會復(fù)制給形參馁蒂,實參和形參使用的是兩個不同內(nèi)存的值呵晚。
// 但形參的值發(fā)生改變時,不會影響實參的值沫屡,從而保證實參數(shù)據(jù)的安全饵隙。
public void Swap(int i, int j)
{
int tmp;
tmp = i;
i = j;
j = tmp;
}
// 按引用傳遞參數(shù)
// 引用參數(shù)是一個對變量的內(nèi)存位置的引用。
// 按引用傳遞參數(shù)時谁鳍,與值參數(shù)不同的時癞季,不會為參數(shù)創(chuàng)建新的存儲位置劫瞳。
// 引用參數(shù)表示與提供方法的實際參數(shù)具有相同的內(nèi)存位置倘潜。
// C#中使用ref關(guān)鍵字聲明引用參數(shù)
public void RefSwap(ref int i, ref int j)
{
int tmp;
tmp = i;
i = j;
j = tmp;
}
// 按輸出傳遞參數(shù)
// return 語句可用于只從函數(shù)中返回一個值,使用輸出參數(shù)可從函數(shù)中返回多個值志于。
// 輸出參數(shù)會把方法輸出的數(shù)據(jù)賦給自己涮因,其他方面與引用參數(shù)相似。
public void Output(out int i, out int j)
{
// 提供給輸出參數(shù)的變量不需要賦值
// 當(dāng)需要從一個參數(shù)沒有指定初始化的方法中返回值時伺绽,輸出參數(shù)特別有用养泡。
i = Convert.ToInt32(Console.ReadLine());
j = Convert.ToInt32(Console.ReadLine());
}
// 入口點
static void Main(string[] args)
{
NumberManipulator nm = new NumberManipulator();
/*
int i = Convert.ToInt32(Console.ReadLine());
int j = Convert.ToInt32(Console.ReadLine());
int max = nm.Max(i, j);
Console.WriteLine("i = {0}, j = {1}, max = {2}", i, j, max);
int i = Convert.ToInt32(Console.ReadLine());
int result = nm.Factorial(i);
Console.WriteLine("i = {0}, result = {1}", i, result);
int i = Convert.ToInt32(Console.ReadLine());
int j = Convert.ToInt32(Console.ReadLine());
nm.Swap(i,j);
Console.WriteLine("i = {0}, j = {1}", i, j);
int i = Convert.ToInt32(Console.ReadLine());
int j = Convert.ToInt32(Console.ReadLine());
nm.RefSwap(ref i, ref j);
Console.WriteLine("i = {0}, j = {1}", i, j);
int i,j;
nm.Output(out i, out j);
Console.WriteLine("i = {0}, j={1}", i, j);
*/
}
}
}
數(shù)組
using System;
namespace ArrayApp
{
class Ary
{
static void Main(string[] args)
{
// 數(shù)組
// 數(shù)組是一個存儲相同類型元素的固定大小的順序集合
// 數(shù)組是用來存儲數(shù)據(jù)的集合嗜湃,數(shù)組是相同類型變量的集合。
// 數(shù)組中指定元素是通過索引來訪問的澜掩,數(shù)組是由連續(xù)的內(nèi)存位置組成的购披。
// 最低的位置對應(yīng)第一個元素,最高的地址對應(yīng)最后一個元素肩榕。
// 聲明數(shù)組
// 聲明數(shù)組不會在內(nèi)存中初始化數(shù)組
int[] arr;
// 初始化數(shù)組
// 當(dāng)初始化數(shù)組變量時刚陡,可賦值給數(shù)組。
// 數(shù)組是引用類型株汉,需使用new來創(chuàng)建數(shù)組的實例筐乳。
arr = new int[10];
// 賦值給數(shù)組
// 通過使用索引賦值給一個單獨的數(shù)組元素
arr[0] = 1;
// 可以在聲明數(shù)組的同時給數(shù)組賦值
double[] darr = {1.1, 2.2, 3.3};
// 可以創(chuàng)建并初始化一個數(shù)組
int[] iarr = new int[3]{1,2,3};
// 創(chuàng)建并初始化數(shù)組時可以省略數(shù)組的大小
int[] iary = new int[]{3,2,1};
// 可賦值數(shù)組變量到另一個目標(biāo)數(shù)組變量中
// 此時目標(biāo)和源會指向相同的內(nèi)存位置
int[] src = new int[]{10,20,30};
int[] dst = src;
// 創(chuàng)建數(shù)組時,C#編譯器會根據(jù)數(shù)組類型乔妈,隱式初始化每個數(shù)組元素為一個默認(rèn)值蝙云。
// int數(shù)組的所有元素都會被初始化為0
// 訪問數(shù)組元素
// 元素通過帶索引的數(shù)組名稱來訪問
int score = dst[1];
// 遍歷數(shù)組
foreach(int i in dst)
{
Console.WriteLine("Element = {0}", i);
}
for(int j = 0; j < src.Length; j++)
{
Console.WriteLine("Item[{0}] = {1}", j, dst[j]);
}
Console.ReadLine();
}
}
}
字符串
using System;
namespace StringApp
{
class Str
{
static void Main(string[] args)
{
// 字符串
// C#中可使用字符數(shù)組表示數(shù)組,可使用string關(guān)鍵字聲明字符串變量路召。
// string關(guān)鍵字是System.String類的別名
// 通過給string變量指定一個字符串
string firstname, lastname;
firstname = "Bruce";
lastname = "Lee";
// 字符串連接
string fullname = firstname + lastname;
Console.WriteLine(fullname);//BruceLee
//通過使用String類構(gòu)造函數(shù)
char[] letters = {'a', 'n', 't', 'm', 'a', 'n'};
string nickname = new string(letters);
Console.WriteLine(nickname);//antman
//通過方法返回字符串
string[] msgs = {"GNU", "is","Not","UNIX"};
string message = String.Join(" ", msgs);
Console.WriteLine(message);//GNU is Not UNIX
//用于轉(zhuǎn)化值得格式化方法
DateTime dt = new DateTime(2018, 7, 26, 12, 30, 00);
string datetime = String.Format("{0:d} {0:t}",dt);
Console.WriteLine(datetime);//2018/7/26 12:30
Console.ReadLine();
}
}
}
結(jié)構(gòu)體
using System;
namespace StructApp{
// 結(jié)構(gòu)體
// 結(jié)構(gòu)體是值類型的數(shù)據(jù)結(jié)構(gòu)
// 結(jié)構(gòu)體使得單一變量可存儲各種數(shù)據(jù)類型的數(shù)據(jù)勃刨。
// 結(jié)構(gòu)體使用struct關(guān)鍵字創(chuàng)建
// 結(jié)構(gòu)體是用來代表一個記錄
public struct Kv
{
//結(jié)構(gòu)體聲明字段無法賦初值,類可以股淡。
private string key;
private string val;
// 結(jié)構(gòu)體的構(gòu)造函數(shù)中朵你,必須為結(jié)構(gòu)體所有字段賦初值,類的構(gòu)造函數(shù)無此限制揣非。
public Configs(string _key, string _val)
{
this.key = _key;
this.val = _val;
}
public string getKey(){
return key;
}
public string getVal(){
return val;
}
}
// 結(jié)構(gòu)體是值類型抡医,類是引用類型。
// 結(jié)構(gòu)體不支持繼承
// 結(jié)構(gòu)體不能聲明默認(rèn)的構(gòu)造函數(shù)
public class StructCls
{
public static void Main(string[] args)
{
Kv app = new Kv("appid","va2lq2en1");
Kv web = new Kv("website","http://yourname.com");
Console.WriteLine("{0}:{1}", app.getKey(), app.getVal());
Console.WriteLine("{0}:{1}", web.getKey(), web.getVal());
Console.ReadLine();
}
}
}
枚舉
using System;
namespace EnumApp
{
class EnumCls
{
// 枚舉
// 枚舉是一組命名整型常量早敬,枚舉是值類型忌傻,也就是說,枚舉包含自己的值搞监,不能繼承或傳遞繼承水孩。
// 枚舉列表中每個符號代表一個整數(shù)值,一個比它前面的符號大的整數(shù)值琐驴。
// 默認(rèn)情況下俘种,第一個枚舉符號的值為0。
public enum Week {Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday};
public static void Main(string[] args)
{
int sun = (int)Week.Sunday;
int mon = (int)Week.Monday;
int tues = (int)Week.Tuesday;
//Sunday:0, Monday:1, Tuesday:2
Console.WriteLine("Sunday:{0}, Monday:{1}, Tuesday:{2}", sun, mon, tues);
Console.ReadLine();
}
}
}
類
using System;
namespace ClsApp
{
// 類的定義
// 類的定義以關(guān)鍵字class開始绝淡,后跟類名宙刘。
// 類的默認(rèn)訪問標(biāo)識符是internal
// 類的陳云默認(rèn)訪問標(biāo)識符為private
internal class Cls{
// 成員變量
// 成員變量是對象的屬性,且保持私有來實現(xiàn)封裝牢酵,只能使用公共成員函數(shù)來訪問悬包。
private double length;
private double width;
private double height;
// 靜態(tài)變量
// 靜態(tài)變量用于定義常量,其值直接調(diào)用類而無需創(chuàng)建類的實例來獲取馍乙。
// 靜態(tài)變量在成員函數(shù)或類的定義外部進(jìn)行初始化布近,也可在類的定義內(nèi)部初始化靜態(tài)變量垫释。
public static double PI;
//public static double PI = 3.14;//錯誤:類、結(jié)構(gòu)或接口成員聲明中的標(biāo)記“=”無效
//public static count;//類撑瞧、結(jié)構(gòu)或接口成員聲明中的標(biāo)記“;”無效
public static int count;//類棵譬、結(jié)構(gòu)或接口成員聲明中的標(biāo)記“;”無效
// 構(gòu)造函數(shù)
// 類的構(gòu)造函數(shù)是類的特殊成員函數(shù)
// 當(dāng)創(chuàng)建類的新對象時自動執(zhí)行
// 構(gòu)造函數(shù)的名稱與類名完全相同,且無返回值预伺。
// 默認(rèn)構(gòu)造函數(shù)無參數(shù)茫船,有參數(shù)的構(gòu)造函數(shù)稱為參數(shù)化構(gòu)造函數(shù)。
// 參數(shù)化構(gòu)造函數(shù)在創(chuàng)建對象時給對象賦初始值
// public void Cls(){} //錯誤成員名稱不能與它們的封閉類型相同
Cls(double _length = 0.0, double _width = 0.0, double _height = 0.0)
{
Console.WriteLine("對象已創(chuàng)建");
length = _length;
width = _width;
height = _height;
}
// 析構(gòu)函數(shù)
// 析構(gòu)函數(shù)是類的特殊成員函數(shù)
// 當(dāng)類的對象超出范圍時執(zhí)行
// 析構(gòu)函數(shù)名稱是在類名前加上波浪號~作為前綴
// 析構(gòu)函數(shù)無返回值且無參數(shù)
// 析構(gòu)函數(shù)用于在結(jié)束程序之前釋放資源
// 析構(gòu)函數(shù)不能繼承或重載
~Cls()
{
Console.WriteLine("對象已銷毀");
}
// 成員函數(shù)
// 類的成員函數(shù)是在類定義中有它的定義或原型的函數(shù)
// 作為類的成員扭屁,能在類的任何對象上操作算谈,且能訪問該對象的類的所有成員。
public void SetLength(double _length = 0.0)
{
length = _length;
}
public double GetLength(){
return length;
}
public double GetVolume()
{
return length * width * height;
}
// 靜態(tài)變量可在成員或類的外部進(jìn)行初始化料滥,也可在類的定義內(nèi)部初始化然眼。
public void SetCount()
{
count++;
}
public int GetCount()
{
return count;
}
// 靜態(tài)函數(shù)
// 靜態(tài)函數(shù)只能訪問靜態(tài)變量
// 靜態(tài)函數(shù)在對象被創(chuàng)建之前就已經(jīng)存在
// 靜態(tài)函數(shù)無需實例化即可調(diào)用
public static double GetArea(double radius = 0.0)
{
return PI * radius;
}
// 入口點
private static void Main(string[] args)
{
Cls cls = new Cls(1.0, 2.0, 3.0);
double result = cls.GetVolume();
Console.WriteLine("volumn = {0}", result);
/*
double input = Convert.ToDouble(Console.ReadLine());
Cls.PI = 3.14;
double area = Cls.GetArea(input);
Console.WriteLine("area = {0}", area);
Console.ReadLine();
*/
}
}
}
繼承
using System;
namespace InheritanceApp
{
// 基類
// 一個類可派生自多個類或接口,意味著類可從多個基類或接口繼承數(shù)據(jù)和函數(shù)葵腹。
class Shape
{
protected double width;
protected double height;
public Shape(double _width, double _height)
{
width = _width;
height = _height;
}
public void SetWidth(double _width)
{
width = _width;
}
public void SetHeight(double _height)
{
height = _height;
}
}
// 派生類
class Rectangle:Shape
{
private double area;
// 基類初始化
// 派生類繼承了基類的成員變量和函數(shù)高每,父類對象應(yīng)在子類對象創(chuàng)建前被創(chuàng)建,可在成員初始化列表中進(jìn)行父類的初始化践宴。
public Rectangle(double _width, double _height):base(_width, _height)
{
area = width * height;
}
public double GetArea()
{
return area;
}
public double GetCost(double _price){
return area * _price;
}
}
class Test
{
static void Main(string[] args)
{
Rectangle rect = new Rectangle(10.0, 20.0);
Console.WriteLine("area = {0}, cost = {1}", rect.GetArea(), rect.GetCost(5.5));
Console.ReadLine();
}
}
}
多態(tài)
using System;
namespace App
{
class Print
{
// 函數(shù)重載
static void Out(int i)
{
Console.WriteLine("{0}",Convert.ToInt32(i));
Console.ReadLine();
}
static void Out(double d)
{
Console.WriteLine("{0}",Convert.ToDouble(d));
Console.ReadLine();
}
static void Out(string s)
{
Console.WriteLine("{0}",Convert.ToString(s));
Console.ReadLine();
}
static void Main(string[] args)
{
Print.Out(1);
Print.Out(1.1);
Print.Out("hello");
}
}
}
獲取系統(tǒng)相關(guān)信息
using System;
using System.Collections.Generic;
namespace App
{
public class OS
{
public static Dictionary<string, string> GetOS()
{
int major = System.Environment.OSVersion.Version.Major;
int minor = System.Environment.OSVersion.Version.Minor;
string[] arr = {Convert.ToString(major), Convert.ToString(minor)};
string osVersion = string.Join(".", arr);
string osName = "";
switch(osVersion){
case "5.0":
osName = "Windows2000";
break;
case "5.1":
osName = "WindowsXP";
break;
case "5.2":
osName = "Windows2003";
break;
case "6.0":
osName = "Windows2008";
break;
case "6.1":
osName = "Windows7";
break;
case "6.2":
osName = "Windows8";
break;
case "10.0":
osName = "Windows10";
break;
default:
osName = "Unknown";
break;
}
Dictionary<string, string> dict = new Dictionary<string, string>();
dict.Add("OSVersion", osVersion);
dict.Add("OSName", osName);
return dict;
}
public static Dictionary<string, string> GetIp()
{
string hostname = System.Net.Dns.GetHostName();
System.Net.IPHostEntry ipEntry = System.Net.Dns.GetHostEntry(hostname);
string ip = ipEntry.AddressList[1].ToString();
Dictionary<string,string> dict = new Dictionary<string, string>();
dict.Add("HostName", hostname);
dict.Add("IP", ip);
return dict;
}
static void Main(string[] args)
{
foreach(KeyValuePair<string, string> kvp in OS.GetIp())
{
Console.WriteLine("{0}:{1}",kvp.Key, kvp.Value);
}
//操作系統(tǒng)信息
OperatingSystem os = System.Environment.OSVersion;
Console.WriteLine("Platform:{0}, ServicePack:{1}, Version:{2}, VersionString:{3}", os.Platform, os.ServicePack, os.Version, os.VersionString);
Console.WriteLine("CLR Version:{0}", System.Environment.Version);
//檢查程序運行時間
System.Diagnostics.Stopwatch timer = new System.Diagnostics.Stopwatch();
timer.Start();
decimal total = 0;
for(int i=0; i<100000; ++i){
total = total + (decimal)Math.Sqrt(i);
}
timer.Stop();
Console.WriteLine("ElapsedMilliseconds:{0}, ElapsedTime:{1}", timer.ElapsedMilliseconds, timer.Elapsed);
}
}
}
MVC開發(fā)所使用的C#語言特性
使用自動實現(xiàn)的屬性
常規(guī)的C#屬性可以暴露類的數(shù)據(jù)片段鲸匿,這種數(shù)據(jù)片段與設(shè)置和接收數(shù)據(jù)采取了一種松耦合的方式。
// 定義屬性
namespace App.Models{
public class Product{
//字段 name
private string name;
//在類中定義屬性 Name阻肩,屬性是帶有g(shù)etter带欢、setter塊的成員
public string Name{
get {return name;}//讀取塊
set{name = value;}//設(shè)置塊
}
}
}
// 在控制器中使用屬性
namespace App.Controllers{
public class HomeController : Controller {
public ViewResult Index(){
// 創(chuàng)建新的Product對象
Product product = new Product();
// 設(shè)置屬性值
product.Name = "alice";
// 讀取屬性
string productName = product.Name;
// 生成視圖
return View("Result", (object)String.Format("product name is {0}", productName));
}
}
}
屬性要具有靈活性,沒有重復(fù)的getter
和setter
烤惊,解決辦法是使用自動實現(xiàn)的屬性乔煞,也稱為“Automatic Property”自動屬性。利用自動屬性柒室,可采用字段支持式屬性模式渡贾,而無需定義該字段或在getter
或setter
中指定代碼主籍。
//自動實現(xiàn)的屬性
namespace App.Models{
public class Product{
// 并未定義getter和setter的體谊惭,也未定義該屬性返回的字段,兩者由C#編譯器在類被編譯時自動完成驶忌。
public int ProductID {get; set;}
// 使用自動屬性與使用規(guī)則屬性沒什么不同
public string Name{get; set;}
// 使用自動屬性可減少一些輸入擂仍,形成更易于閱讀的代碼囤屹,但仍能保持屬性的靈活性。
// 若需改變一個屬性的實現(xiàn)方式防楷,還可返回到規(guī)則屬性的格式牺丙。
public decimal Price{get; set;}
}
}
將自動屬性切換成規(guī)則屬性
namespace App.Models{
public class Product{
//字段
private string name;
// 自動屬性
public int ProductID {get; set;}
// 規(guī)則屬性:必須同時實現(xiàn)getter和setter,以回到規(guī)則屬性的定義方式复局。
public string Name {
// C#在一個屬性中不支持混用自動和規(guī)則風(fēng)格的getter和setter
get{ return ProductID + name; }
set{ name = value; }
}
}
}
使用對象與集合的初始化器
namespace App.Controllers {
public class HomeController:Controller{
public ViewResult CreateProduct(){
// 創(chuàng)建新的Product對象
Product product = new Product();
// 設(shè)置屬性值
product.ProductID = 100;
product.Name = "alice";
return View("Result", (object)String.Format("product name is {0}", product.Name));
}
}
}
使用對象初始化器(Object Initializer)能夠在一個步驟中創(chuàng)建并填寫實例
// 創(chuàng)建并填充對象
Product product = new Product(){
ProductID = 100,
Name = "alice"
}
類名后調(diào)用的花括號形成了初始化器冲簿,目的是為參數(shù)提供值,以此作為該對象的構(gòu)造過程亿昏。已同樣的特性作為構(gòu)造過程峦剔,也能對集合和數(shù)組的內(nèi)容進(jìn)行初始化。
// 構(gòu)建并初始化一個數(shù)組
string[] strArr = {"Windows", "Linux", "UNIX"}
//構(gòu)建并初始化發(fā)反省集合庫的類
List<init> intList = new List<int> {10, 20, 30};
Dictionary<string, int> dic = new Dictionanry<string, int>{
{"windows", 10},
{"Linux", 20},
{"UNIX", 30}
};
使用擴展方法
擴展方法(Extension Method)指那些不是你擁有的角钩、不能直接修改的類添加方法的一種方便的方式吝沫。
namespace App.Models{
public class ShoppingCart {
// 類中封裝了一個Product對象的列表
public List<Product> Products {get; set;}
}
}
定義擴展方法
namespace App.Models{
public static class ExtensionMethods{
// this關(guān)鍵字把TotalPrices標(biāo)記為一個擴展方法
public static decimal TotalPrices(this ShoppingCart cart){
decimal total = 0;
foreach(Product product in cart.Products){
total += product.Price;
}
return total;
}
}
}
使用擴展方法
namespace App.Controllers{
public class HomeController{
public ViewResult UseExtension(){
// 創(chuàng)建并填充
ShoppingCart cart = new ShoppingCart{
Products = new List<Product>{
new Product {Name = "kayak", Price = 10},
new Product{Name = "ball", Price = 20}
}
};
// 計算購物車總價
decimal total = cart.TotalPrices();
return View("Result", (object)String.Format("total is {0:c}", total));
}
}
}