前言:
在继续学习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私有字段,当属性较多的时候可能要多写很多冗长的代码……
我们既想要灵活的属性,又不想定制复杂的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引入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));
①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查询有一个比较有趣的特性就是延迟执行,如果查询语句包含的都是延迟方法,那么该查询语句直到遍历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));
}
从结果可以看出,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));
}
二、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来取得变量的值。