跟小靜學MVC3[03]--相關語法特性小補習


前言:

在繼續學習MVC3之前,我們先復習一些會用到的c#語法特性,以及最基本的Razor語法常識,為語法不太熟悉的同學補補課,功課較好的同學可以直接跳過了。


一、C#語法特性

首先學習一些以后會用到的C#語法特性,我們新建一個控制台程序來進行簡單的演示。

1.AIP( Automatically Implemented Properties)—自動實現屬性

  • 傳統屬性代碼

對於屬性大家都不陌生,我也不想介紹什么是屬性之類的話題,先看個具體代碼示例:

定義屬性
class Article
    {
        private  string _title;
        public  string Title
        {
            get { return _title; }
            set { _title = value; }
        }
    }
調用屬性
Article article= new Article();
            article.Title = " 大米返利網10月9號提現完畢 ";      

           Console.WriteLine(article.Title);

通過get和set代碼段的封裝,最終Title屬性使用起來的效果就像是在對一個字段進行讀寫一樣方便。屬性相比public字段的優點在於,它可以靈活地在get和set進行一定的邏輯處理,缺點在於要多定義一個private私有字段,當屬性較多的時候可能要多寫很多冗長的代碼……

  • AIP--自動實現屬性

我們既想要靈活的屬性,又不想定制復雜的getter和setter訪問器代碼,怎么辦呢?AIP來幫你。AIP提供了一種創建屬性的簡潔方式,節省了許多敲代碼的時間,提高了可讀性,而且保留了屬性本身的靈活性。

class Article
    {
        public  string Title { get; set; }
    }

使用AIP時有幾點需要注意:

①我們不必再定義getter和setter代碼塊,也不必再顯式定義用於讀寫的私有字段。當編譯程序時這些會由c#編譯器自動完成。

②如果要改變屬性的實現,那么還要回到常規的屬性形式。例如:

private  string _title;
        public  string Title
        {
            get { return  " 標題: "+_title; }
            set { _title = value; }
        }

③c#不支持上述兩種形式的訪問器並存,getter和setter必須同時為常規形式或自動實現形式。

更多關於屬性可以參考:跟小靜讀CLR via C#(11)-無參屬性、索引器

2.Object and Collection Initializers(對象和集合初始化器)

程序員們經常反復做的另外一個工作就是實例化對象並對其屬性逐個賦值,然后調用方法。為了簡化這一過程,C#為我們提供了新的語法糖--對象集合初始化器。           

創建對象3步
Article article= new Article();
            article.Title = " 大米返利網10月9號提現完畢 ";
            article.PublishTime = DateTime.Now;
            Save(article);

通過對象初始化器,這三步走可以一步到位:

Save( new Article
                {
                         Title = " 大米返利網10月9號提現完畢 ",
                         PublishTime = DateTime.Now
                });

類似的語法也可以用於數組,List,Dictionary等,這里不再贅述。

3. 擴展方法

如果想為未開源或不能直接修改的類添加方法該怎么辦呢?擴展方法提供了一條捷徑。假設現在我們有下面這個類ArticleList:

public  class ArticleList
    {
        public IList<Article> Articles;
    }

現在想為其添加一個方法用來統計文章數目,但是ArticleList.cs的源碼不允許修改,我們就可以使用擴展方法來添加:

public  static  int GetTotal( this ArticleList list,DateTime time)
        {
            int total = 0;
            foreach ( var article in list.Articles)
            {
                if (Convert.ToDateTime(article.PublishTime) <= time)
                    total++;
            }
            return total;
        }
調用
ArticleList articles = new ArticleList
                                       {
                                           Articles = new List<Article>
                                                          {
                                                              new Article {PublishTime = " 2012-9-1 ", Title = " 好聲音吉克雋逸 "},
                                                              new Article {PublishTime = " 2012-8-15 ", Title = " 5款新款皮衣 "},
                                                              new Article {PublishTime = " 2012-10-30 ", Title = " 本月返現排行 "}
                                                          }
                                       };
            Console.WriteLine(articles.GetTotal(DateTime.Now));

擴展方法定義:

  • 定義一個靜態類,名稱不限;
  • 定義靜態方法,第一個參數類型為要擴展的目標類型;為了表明是擴展方法,還要給第一個參數添加this關鍵字。

更多關於擴展方法可參考:跟小靜讀CLR via C#(09)-擴展方法

4. Lamda 表達式

  • lamda表達式引入

Lamda表達式使用非常廣泛,我們從小例子逐漸熟悉它。為了提高可維護性,我們將上面的例子使用委托,改造成下面這樣

lamda引入1
public  static  int GetTotal( this ArticleList list, Func<Article, bool> func)
       {
           int total = 0;
           foreach ( var article in list.Articles)
           {
               if (func(article))
                   total++;
           }
           return total;
       }

調用:

Func<Article, bool> func = delegate(Article article) { return article.PublishTime <= DateTime.Now; };
Console.WriteLine(articles.GetTotal(func));

在上面的寫法中,我們可以在委托里定義自己的過濾標准,美中不足的是需要為每個過濾標准定義一個Func。好在我們有另外一種簡潔的委托形式來替換上述冗長的寫法—lamda表達式:

Func<Article, bool> func =article=>article.PublishTime <= DateTime.Now;
Console.WriteLine(articles.GetTotal(func));

lamda表達式使用“=>”表達式來鏈接參數和表達式的結果。

上面的兩行表達式可以進一步合並:

Console.WriteLine(articles.GetTotal(article => article.PublishTime <= DateTime.Now));
  • 幾種常用lamda表達式形式:
①article=>GetArticle(article):

lamda表達式不不含其它邏輯處理;

②(article,time) =>article.Title.Contains( " 提現 ")&&article.PublishTime<=time

如果lamda表達式有多個參數,需要用圓括號括起來。

③(articles,keyword, int)=>{……… return result;}

當lamda表達式的語句大於一行時,要使用花括號寫成代碼段,以return 結束返回結果。

5. 自動類型推斷--var

var變量允許定義隱式類型的變量,編譯時c#編譯器會自動識別類型。

var article = new Article {PublishTime = DateTime.Parse( " 2012-9-1 "), Title = " 好聲音吉克雋逸 "};

6. 匿名類型

將前面的對象初始化器和自動類型推斷結合起來,得到了一種十分簡便的寫法:

var article = new {
             PublishTime = DateTime.Parse( " 2012-9-1 "),
             Title = " 好聲音吉克雋逸 "
         };

這里的article是匿名類型的對象,但是這跟javascript里的動態類型是不同的。它仍然是強類型的,只不過編譯器能自動推斷出變量所屬的類型。如果兩個變量的屬性名稱及屬性類型完全一致,那么他們會被推斷為相同類型,即便該類型並沒有預先定義,也會自動產生。

var articles = new[]
                    {
                         new {Name = " a ", price = 10},
                         new {Name = " b ", price = 20}
                    };
Console.WriteLine(articles[ 0].Name);

7.LINQ(集成查詢語言)

  • 查詢語法

前面幾點語法特性其實都是為了LINQ做鋪墊的,LINQ是在class中查詢數據的類SQL語法。


Article[] articles = new[]{
                                         new Article {Title = " 好聲音吉克雋逸 ", Order = 14},
                                         new Article {Title = " 5款新款皮衣 ", Order = 1},
                                         new Article {Title = " 本月返現排行 ", Order = 28}
                                     };

           var result = from article in articles
                         orderby article.Order descending
                         select new
                                    {
                                        article.Order, article.Title
                                    };

            foreach ( var article in result)
            {
                Console.WriteLine( string.Format( " {0}:{1} ", article.Order, article.Title));
            }
  • 表達式語法:除了上述較為嚴格的查詢語法外,我們還可以選擇使用點表示法,這其實是一些擴展方法,需要引用命名空間System.LINQ。
var result = articles.OrderByDescending(a => a.Order)  // 倒序
                .Take( 2)          // 取前兩條
                .Select(a => new {a.Order, a.Title}); // 返回結果

其中OrderByDescending是用來進行排序,Take是取前N條記錄,select產生指定形式的結果。此外,還有很多常用的LINQ擴展方法,這里不再一一列舉。

  • LINQ延遲執行

LINQ查詢有一個比較有趣的特性就是延遲執行,如果查詢語句包含的都是延遲方法,那么該查詢語句直到遍歷IEnumerable<T>結果時才會被執行。例如上面的例子改造一下:

LINQ延遲
Article[] articles = new[]{
                                         new Article {Title = " 好聲音吉克雋逸 ", Order = 14},
                                         new Article {Title = " 5款新款皮衣 ", Order = 1},
                                         new Article {Title = " 本月返現排行 ", Order = 28}
                                     };
var result = articles.OrderByDescending(a => a.Order)
                .Take( 2)
                .Select(a => new { a.Order, a.Title });
            foreach ( var article in result)
            {
                Console.WriteLine( string.Format( " {0}:{1} ", article.Order, article.Title));
            }
            articles[ 0].Title = " 測試測試 ";
            foreach ( var article in result)
            {
                Console.WriteLine( string.Format( " {0}:{1} ", article.Order, article.Title));
            }

image

從結果可以看出,linq語句並沒有立即執行,所以對article[0]重新賦值仍然能夠奏效。如果查詢語句中包含非延遲執行的方法,那么就會立即執行,例如我們加上ToList()后的效果:

ToList()不延遲
var result = articles.OrderByDescending(a => a.Order)
                .Take( 2)
                .Select(a => new { a.Order, a.Title }).ToList();
            articles[ 0].Title = " 測試測試 ";
            foreach ( var article in result)
            {
                Console.WriteLine( string.Format( " {0}:{1} ", article.Order, article.Title));
            }

image


二、Razor語法預熱

1.在關注Razor語法之前,我們先做些准備工作。新建model和controller,並創建對應的view。

model
public  class Product
{
    ///   <summary>
   
/// 商品id
   
///   </summary>
    public  int Id { get; set; }
    ///   <summary>
   
/// 商品名稱
   
///   </summary>
    public  string Name { get; set; }

    ///   <summary>
   
/// 圖片地址
   
///   </summary>
    public  string Img { get; set; }
    ///   <summary>
   
/// 商品價格
   
///   </summary>
    public  decimal Price { get; set; }
    ///   <summary>
   
/// 大米返現金額
   
///   </summary>
    public  decimal Rebate { get; set; }
}
controller
public  class ProductController : Controller
    {
        public ActionResult Index()
        {
            Product product = new Product
                                  {
                                      Id = " MTkxMzExNjA3MzF7cWRjeDExMDl9 ",
                                      Name = " 繽慕 韓版休閑男裝秋裝 男士長袖t恤 ",
                                      Price = 88,
                                      Rebate = 12
                                  };

            ViewBag.time = DateTime.Now;
            return View(product);
        }
    }

2.創建View

@model DamifanliMvc3.Models.Product
@{
    ViewBag.Title = " 商品 ";
}
@{
    string url = "http://www.damifanli.com/view-@(Model.Id).html";
}

<h2><a href= " @url " target= " _blank "> @Model.Name</a></h2><br/>
一口價:¥@Model.Price,
@if(Model.Rebate> 0)
{
    @:大米返利網返:¥@Model.Rebate
}
else
{
    <text>該商品暫無返現活動,希望您繼續關注。 </text>
}
<br/><a href= " @url " target= " _blank "><img src= " @Model.Img "/></a>

當前時間: @ViewBag.time

幾點說明:

①使用Model對象:@model DamifanliMvc3.Models.Product

Razor語法通常以@符號開頭,強類型View允許將model對象傳遞給view,使用@model定義后可以在接下來反復引用其字段、屬性、方法等。

注意在開頭聲明的時候使用小寫的@model,而在調用的時候要使用大寫的@Model.

②如果要在代碼塊中輸入非HTML開頭的文本,那么可以使用兩種方式:

  • @:輸出內容    (該方式一般用於單行輸出)
  • <text>輸出內容</text>    (該方式一般用於多行輸出)

③多次使用或者公用的變量及代碼可以放在以@開頭的單獨的代碼塊中,如例子中的url變量。

④通過ViewBag傳遞數據,在webform開發中我們經常使用viewstate等來保存變量,在MVC3中我們使用ViewBag來傳遞數據。例如上面的例子中在controller為ViewBag.time賦值,在View中可以使用@ViewBag.time來取得變量的值。

image


免責聲明!

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



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