欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
帶你了解C#每個(gè)版本新特性

上學(xué)時(shí)學(xué)習C#和.NET,當時(shí)網(wǎng)上的資源不像現在這樣豐富,所以去電腦城買(mǎi)了張盜版的VS2005的光盤(pán),安裝時(shí)才發(fā)現是VS2003,當時(shí)有一種被坑的感覺(jué),但也正是如此,讓我有了一個(gè)完整的.NET的學(xué)習生涯。

一直都認為學(xué)習語(yǔ)言應該系統的進(jìn)行學(xué)習,了解每一個(gè)版本的新增特性,才能在實(shí)際應用中做到有的放矢。最近發(fā)現團隊中有不少人雖然用著(zhù)最新的技術(shù),但知識儲備還停留在一個(gè)比較初始的狀態(tài),這樣在編碼過(guò)程中會(huì )走不少彎路。

本文梳理下C#從1.0到7.0版本的一些常用特性,對于不常用的或者我沒(méi)有用到過(guò)的一些特性,會(huì )列出來(lái),但不會(huì )做詳細描述。另外C#8.0現在還沒(méi)有正式推出,并且目前我們也只是在使用dotNet Core2.1,所以C#8.0本文也不會(huì )涉及。

C#1.X

C# VS版本 CLR版本 .NET Framework
1.0 VS2002 1.0 1.0
1.1 VS2003 1.1 1.1

在C#1.0或1.1版本中,從語(yǔ)言的角度就是基本的面向對象的語(yǔ)法,可以說(shuō)任何一本C#語(yǔ)言的書(shū)籍都包含了C#1.X的所有內容。

如果您已經(jīng)在使用C#語(yǔ)言編寫(xiě)代碼,那么C#1.X的相關(guān)知識應該已經(jīng)掌握?;A語(yǔ)法部分這里就不再贅述了。

C#2.0

C# VS版本 CLR版本 .NET Framework
2.0 VS2005 2.0 2.0

2.0中對應VS2005我用的也不多,因為很快就被VS2008替代了,不過(guò)在語(yǔ)言方面卻帶來(lái)了很多新的東西。

泛型

C#2中最重要的一個(gè)特性應該就是泛型。泛型的用處就是在一些場(chǎng)景下可以減少強制轉換來(lái)提高性能。在C#1中就有很多的強制轉換,特別是對一些集合進(jìn)行遍歷時(shí),如ArrayList、HashTable,因為他們是為不同數據類(lèi)型設計的集合,所以他們中鍵和值的類(lèi)型都是object,這就意味著(zhù)會(huì )平凡發(fā)生裝箱拆箱的操作。C#2中有了泛型,所以我們可以使用List、Dictionary<Tkey,TValue> 。泛型能夠帶來(lái)很好的編譯時(shí)類(lèi)型檢查,也不會(huì )有裝箱拆箱的操作,因為類(lèi)型是在使用泛型的時(shí)候就已經(jīng)指定了。

.NET已經(jīng)通過(guò)了很多的泛型類(lèi)型供我們使用,如上面提到的List,Dictionary<Tkey,TValue>,我們也可以自己來(lái)創(chuàng )建泛型類(lèi)型(類(lèi)、接口、委托、結構)或是方法。在定義泛型類(lèi)型或時(shí)可以通過(guò)定義泛型約束來(lái)對泛型參數進(jìn)行限制,更好的使用編譯時(shí)檢查。泛型約束是通過(guò)關(guān)鍵字where來(lái)實(shí)現的,C#2中的泛型約束有4種:

  • 引用類(lèi)型約束:確保類(lèi)型實(shí)參是引用類(lèi)型,使用where T:class來(lái)表示;
  • 值類(lèi)型約束:確保類(lèi)型實(shí)參是值類(lèi)型,使用where T:truct來(lái)表示;
  • 構造函數類(lèi)型約束,使用where T:new()來(lái)表示;
  • 轉換類(lèi)型約束:約束類(lèi)型實(shí)參是另外的一種類(lèi)型,例如:where T:IDisposable 。

分部類(lèi)(Partil)

分部類(lèi)可以允許我們在多個(gè)文件中為一個(gè)類(lèi)型(class、struct、interface)編寫(xiě)代碼,在A(yíng)sp.Net2.0中用的極為廣泛。新建一個(gè)Aspx頁(yè)面,頁(yè)面的CodeBehind和頁(yè)面中的控件的定義就是通過(guò)分部類(lèi)來(lái)實(shí)現的。如下:

public partial class _Default : System.Web.UI.Page 
public partial class _Default 

分部類(lèi)使用關(guān)鍵字partial來(lái)定義,當一個(gè)類(lèi)中的代碼非常多時(shí),可以使用分部類(lèi)來(lái)進(jìn)行拆分,這對代碼的閱讀很有好處,而且不會(huì )影響調用。不過(guò)現在我們前后端分離,后端代碼要做到單一職責原則,不會(huì )有很多大的類(lèi),所以這個(gè)特性很少用到。

靜態(tài)類(lèi)

靜態(tài)類(lèi)中的公用方法必須也是靜態(tài)的,可以由類(lèi)名直接調用,不需要實(shí)例化,比較適用于編寫(xiě)一些工具類(lèi)。如System.Math類(lèi)就是靜態(tài)類(lèi)。工具類(lèi)有一些特點(diǎn),如:所有成員都是靜態(tài)的、不需要被繼承、不需要進(jìn)行實(shí)例化。在C#1中我們可以通過(guò)如下代碼來(lái)實(shí)現:

//聲明為密封類(lèi)防止被繼承 
public sealed class StringHelper
{
    //添加私有無(wú)參構造函ˉ數防止被實(shí)例化,如果不添加私有構造函數 
    //會(huì )自動(dòng)生成共有無(wú)參構造函數 
    private StringHelper(){};
    public static int StringToInt32(string input)
    {
        int result=0;
        Int32.TryParse(input, out result);
        return result;
    }
}

C#2中可以使用靜態(tài)類(lèi)來(lái)實(shí)現:

public static class StringHelper
{
    public static int StringToInt32(string input)
    {
        int result=0;
        Int32.TryParse(input, out result);
        return result;
    }
}

屬性的訪(fǎng)問(wèn)級別

在C#1中聲明屬性,屬性中的get和set的訪(fǎng)問(wèn)級別是和屬性一致,要么都是public要么都是private,如果要實(shí)現get和set有不同的訪(fǎng)問(wèn)級別,則需要用一種變通的方式,自己寫(xiě)GetXXX和SetXXX方法。在C#2中可以單獨設置get和set的訪(fǎng)問(wèn)級別,如下:

private string _name;
public string Name
{
    get { return _name; }
    private set { _name = value; }
}

需要注意的是,不能講屬性設置為私有的,而將其中的get或是set設置成公有的,也不能給set和get設置相同的訪(fǎng)問(wèn)級別,當set和get的訪(fǎng)問(wèn)級別相同時(shí),我們可以直接設置在屬性上。

命名空間別名

命名空間可以用來(lái)組織類(lèi),當不同的命名空間中有相同的類(lèi)時(shí),可以使用完全限定名來(lái)防止類(lèi)名的沖突,C#1中可以使用空間別名來(lái)簡(jiǎn)化書(shū)寫(xiě),空間別名用using關(guān)鍵字實(shí)現。但還有一些特殊情況,使用using并不能完全解決,所以C#2中提供了下面幾種特性:

  • 命名空間修飾符語(yǔ)法
  • 全局命名空間別名
  • 外部別名

我們在構建命名空間和類(lèi)的時(shí)候,盡量避免出現沖突的情況,這個(gè)特性也較少用到。

友元程序集

當我們希望一個(gè)程序集中的類(lèi)型可以被外部的某些程序集訪(fǎng)問(wèn),這時(shí)如果設置成Public,就可以被所有的外部程序集訪(fǎng)問(wèn)。怎樣只讓部分程序集訪(fǎng)問(wèn),就要使用友元程序集了,具體參考之前的博文《C#:友元程序集(http://blog.fwhyy.com/2010/11/csharp-a-friend-assembly/)

可空類(lèi)型

可空類(lèi)型就是允許值類(lèi)型的值為null。通常值類(lèi)型的值是不應該為null的,但我們很多應用是和數據庫打交道的,而數據庫中的類(lèi)型都是可以為null值的,這就造成了我們寫(xiě)程序的時(shí)候有時(shí)需要將值類(lèi)型設置為null。在C#1中通常使用”魔值“來(lái)處理這種情況,比如DateTiem.MinValue、Int32.MinValue。在A(yíng)DO.NET中所有類(lèi)型的空值可以用DBNull.Value來(lái)表示。C#2中可空類(lèi)型主要是使用System.Nullable的泛型類(lèi)型,類(lèi)型參數T有值類(lèi)型約束??梢韵裣旅孢@樣來(lái)定義可空類(lèi)型:

Nullable<int> i = 20;
Nullable<bool> b = true;

C#2中也提供了更方便的定義方式,使用操作符?:

int? i = 20;
bool? b = true;

迭代器

C#2中對迭代器提供了更便捷的實(shí)現方式。提到迭代器,有兩個(gè)概念需要了解

  • 可枚舉對象和枚舉器,實(shí)現了System.Collections.IEnumerable接口的對象是可枚舉對象,這些對象可以被C#中的foreach進(jìn)行迭代;
  • 實(shí)現了System.Collections.IEnumeror接口的對象被稱(chēng)為枚舉器。在C#1中實(shí)現迭代器非常繁瑣,

看下面一個(gè)例子:

public class Test 
{
    static void Main()
    {
        Person arrPerson = new Person("oec2003","oec2004","oec2005");
        foreach (string p in arrPerson)
        {
            Console.WriteLine(p);
        }
        Console.ReadLine();
    }
}
public class Person:IEnumerable 
{
    public Person(params string[] names)
    {
        _names = new string[names.Length];
        names.CopyTo(_names, 0);
    }
    public string[] _names;
    public IEnumerator GetEnumerator()
    {
        return new PersonEnumerator(this);
    }
    private string this[int index]
    {
        get { return _names[index]; }
        set { _names[index] = value; }
    }
}
public class PersonEnumerator : IEnumerator 
{
    private int _index = -1;
    private Person _p;
    public PersonEnumerator(Person p) { _p = p; }
    public object Current
    {
        get { return _p._names[_index]; }
    }
    public bool MoveNext()
    {
        _index++;
        return _index < _p._names.Length;
    }
    public void Reset()
    {
        _index = -1;
    }
}

C#2中的迭代器變得非常便捷,使用關(guān)鍵字yield return關(guān)鍵字實(shí)現,下面是C#2中使用yield return的重寫(xiě)版本:

public class Test 
{
    static void Main()
    {
        Person arrPerson = new Person("oec2003","oec2004","oec2005");
        foreach (string p in arrPerson)
        {
            Console.WriteLine(p);
        }
        Console.ReadLine();
    }
}
public class Person:IEnumerable 
{
    public Person(params string[] names)
    {
        _names = new string[names.Length];
        names.CopyTo(_names, 0);
    }
    public string[] _names;
    public IEnumerator GetEnumerator()
    {
        foreach (string s in _names)
        {
            yield return s;
        }
    }
}

匿名方法

匿名方法比較適用于定義必須通過(guò)委托調用的方法,用多線(xiàn)程來(lái)舉個(gè)例子,在C#1中代碼如下:

private void btnTest_Click(object sender, EventArgs e)
{
    Thread thread = new Thread(new ThreadStart(DoWork));
    thread.Start();
}
private void DoWork()
{
    for (int i = 0; i < 100; i++)
    {
        Thread.Sleep(100);
        this.Invoke(new Action<string>(this.ChangeLabel),i.ToString());
    }
}
private void ChangeLabel(string i)
{
    label1.Text = i + "/100";
}

使用C#2中的匿名方法,上面的例子中可以省去DoWork和ChangeLabel兩個(gè)方法,代碼如下:

private void btnTest_Click(object sender, EventArgs e)
{
    Thread thread = new Thread(new ThreadStart(delegate() {
        for (int i = 0; i < 100; i++)
        {
            Thread.Sleep(100);
            this.Invoke(new Action(delegate() { label1.Text = i + "/100"; }));
        }
    }));
    thread.Start();
}

其他相關(guān)特性

  • 固定大小緩沖區(Fixed-size buffers)
  • 編譯指令(Pragma directives)
  • 委托的逆變協(xié)變

C#3.0

C# VS版本 CLR版本 .NET Framework
3.0 VS2008 2.0 3.0 3.5

如果說(shuō)C#2中的核心是泛型的話(huà),那么C#3中的核心就應是Linq了,C#3中的特性幾乎都是為L(cháng)inq服務(wù)的,但每一項特性都可以脫離Linq來(lái)使用。下面就來(lái)看下C#3中有哪些特性。

自動(dòng)實(shí)現的屬性

這個(gè)特性非常簡(jiǎn)單,就是使定義屬性變得更簡(jiǎn)單了。代碼如下:

public string Name { get; set; }
public int Age { private set; get; }

隱式類(lèi)型的局部變量和擴展方法

隱式類(lèi)型的局部變量是讓我們在定義變量時(shí)可以比較動(dòng)態(tài)化,使用var關(guān)鍵字作為類(lèi)型的占位符,然后由編譯器來(lái)推導變量的類(lèi)型。

擴展方法可以在現有的類(lèi)型上添加一些自定義的方法,比如可以在string類(lèi)型上添加一個(gè)擴展方法ToInt32,就可以像“20”.ToInt32()這樣調用了。

具體參見(jiàn)《C#3.0學(xué)習(1)—隱含類(lèi)型局部變量和擴展方法(http://blog.fwhyy.com/2008/02/learning-csharp-3-0-1-implied-type-of-local-variables-and-extension-methods/)》。

隱式類(lèi)型雖然讓編碼方便了,但有些不少限制:

  • 被聲明的變量只能是局部變量,而不能是靜態(tài)變量和實(shí)例字段;
  • 變量在聲明的同時(shí)必須初始化,初始化值不能為null;
  • 語(yǔ)句中只能聲明一個(gè)變量;

對象集合初始化器

簡(jiǎn)化了對象和集合的創(chuàng )建,具體參見(jiàn)《C#3.0學(xué)習(2)—對象集合初始化器(http://blog.fwhyy.com/2008/02/learning-c-3-0-2-object-collection-initializer/)》。

隱式類(lèi)型的數組

和隱式類(lèi)型的局部變量類(lèi)似,可以不用顯示指定類(lèi)型來(lái)進(jìn)行數組的定義,通常我們定義數組是這樣:

string[] names = { "oec2003", "oec2004", "oec2005" };

使用匿名類(lèi)型數組可以想下面這樣定義:

protected void Page_Load(object sender, EventArgs e)
{
    GetName(new[] { "oec2003", "oec2004", "oec2005" });
}
public string GetName(string[] names)
{
    return names[0];
}

匿名類(lèi)型

匿名類(lèi)型是在初始化的時(shí)候根據初始化列表自動(dòng)產(chǎn)生類(lèi)型的一種機制,利用對象初始化器來(lái)創(chuàng )建匿名對象的對象,具體參見(jiàn)《C#3.0學(xué)習(3)—匿名類(lèi)型(http://blog.fwhyy.com/2008/03/learning-csharp-3-0-3-anonymous-types/)》。

Lambda表達式

實(shí)際上是一個(gè)匿名方法,Lambda表達的表現形式是:(參數列表)=>{語(yǔ)句},看一個(gè)例子,創(chuàng )建一個(gè)委托實(shí)例,獲取一個(gè)string類(lèi)型的字符串,并返回字符串的長(cháng)度。代碼如下:

Func<string, int> func = delegate(string s) { return s.Length; };
Console.WriteLine(func("oec2003"));

使用Lambda的寫(xiě)法如下:

Func<string, int> func = (string s)=> { return s.Length; };
Func<string, int> func1 = (s) => { return s.Length; };
Func<string, int> func2 = s => s.Length;

上面三種寫(xiě)法是逐步簡(jiǎn)化的過(guò)程。

Lambda表達式樹(shù)

是.NET3.5中提出的一種表達方式,提供一種抽象的方式將一些代碼表示成一個(gè)對象樹(shù)。要使用Lambda表達式樹(shù)需要引用命名空間System.Linq.Expressions,下面代碼構建一個(gè)1+2的表達式樹(shù),最終表達式樹(shù)編譯成委托來(lái)得到執行結果:

Expression a = Expression.Constant(1);
Expression b = Expression.Constant(2);
Expression add = Expression.Add(a, b);
Console.WriteLine(add); //(1+2) Func<int> fAdd = Expression.Lambda<Func<int>>(add).Compile();
Console.WriteLine(fAdd()); //3 

Lambda和Lambda表達式樹(shù)為我們使用Linq提供了很多支持,如果我們在做的一個(gè)管理系統使用了Linq To Sql,在列表頁(yè)會(huì )有按多個(gè)條件來(lái)進(jìn)行數據的篩選的功能,這時(shí)就可以使用Lambda表達式樹(shù)來(lái)進(jìn)行封裝查詢(xún)條件,下面的類(lèi)封裝了And和Or兩種條件:

public static class DynamicLinqExpressions 
{
    public static Expression<Func<T, bool>> True<T>() { return f => true; }
    public static Expression<Func<T, bool>> False<T>() { return f => false; }

    public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expr1,
                                                        Expression<Func<T, bool>> expr2)
    {
        var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
        return Expression.Lambda<Func<T, bool>>
              (Expression.Or(expr1.Body, invokedExpr), expr1.Parameters);
    }

    public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expr1,
                                                         Expression<Func<T, bool>> expr2)
    {
        var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
        return Expression.Lambda<Func<T, bool>>
              (Expression.And(expr1.Body, invokedExpr), expr1.Parameters);
    }
}

下面是獲取條件的方法:

public Expression<Func<Courses, bool>> GetCondition()
{
    var exp = DynamicLinqExpressions.True<Courses>();
    if (txtCourseName.Text.Trim().Length > 0)
    {
        exp = exp.And(g => g.CourseName.Contains(txtCourseName.Text.Trim()));
    }
    if (ddlGrade.SelectedValue != "-1")
    {
        exp=exp.And(g => g.GradeID.Equals(ddlGrade.SelectedValue));
    }
    return exp;
}

Linq

Linq是一個(gè)很大的話(huà)題,也是NET3.5中比較核心的內容,有很多書(shū)籍專(zhuān)門(mén)來(lái)介紹Linq,下面只是做一些簡(jiǎn)單的介紹,需要注意的是Linq并非是Linq To Sql,Linq是一個(gè)大的集合,里面包含:

  • Linq To Object:提供對集合和對象的處理;
  • Linq To XML:應用于XML;
  • Linq To Sql:應用于SqlServer數據庫;
  • Linq To DataSet: DataSet;
  • Linq To Entities:應用于SqlServer之外的關(guān)系數據庫,我們還可以通過(guò)Linq的擴展框架來(lái)實(shí)現更多支持Linq的數據源。

下面以L(fǎng)inq To Object為例子來(lái)看看Linq是怎么使用的:

public class UserInfo 
{
    public string Name { get; set; }
    public int Age { get; set; }
}
public class Test 
{
    static void Main()
    {
        List<UserInfo> users = new List<UserInfo>()
        {
            new UserInfo{Name="oec2003",Age=20},
            new UserInfo{Name="oec2004",Age=21},
            new UserInfo{Name="oec2005",Age=22}
        };
        IEnumerable<UserInfo> selectedUser = from user in users
                                             where user.Age > 20
                                             orderby user.Age descending select user;
        foreach (UserInfo user in selectedUser)
        {
            Console.WriteLine("姓名:"+user.Name+",年齡:"+user.Age);
        }
        Console.ReadLine();
    }
}

可以看出,Linq可以讓我們使用類(lèi)似Sql的關(guān)鍵字來(lái)對集合、對象、XML等進(jìn)行查詢(xún)。

C#4.0

C# VS版本 CLR版本 .NET Framework
4.0 VS2010 4.0 4.0

可選參數

VB在很早就已經(jīng)支持了可選參數,而C#知道4了才支持,顧名思義,可選參數就是一些參數可以是可選的,在方法調用的時(shí)候可以不用輸入??聪旅娲a:

public class Test 
{
    static void Main()
    {
        Console.WriteLine(GetUserInfo()); //姓名:ooec2003,年齡:30 
        Console.WriteLine(GetUserInfo("oec2004", 20));//姓名:ooec2004,年齡:20 
        Console.ReadLine();
    }
    public static string GetUserInfo(string name = "oec2003", int age = 30)
    {
        return "姓名:" + name + ",年齡:" + age.ToString();
    }
}

命名實(shí)參

命名實(shí)參是在制定實(shí)參的值時(shí),可以同時(shí)指定相應參數的名稱(chēng)。編譯器可以判斷參數的名稱(chēng)是否正確,命名實(shí)參可以讓我們在調用時(shí)改變參數的順序。命名實(shí)參也經(jīng)常和可選參數一起使用,看下面的代碼:

static void Main()
{
    Console.WriteLine(Cal());//9 
    Console.WriteLine(Cal(z: 5, y: 4));//25 
    Console.ReadLine();
}
public static int Cal(int x=1, int y=2, int z=3)
{
    return (x + y) * z;
}

通過(guò)可選參數和命名參數的結合使用,我們可以減少代碼中方法的重載。

動(dòng)態(tài)類(lèi)型

C#使用dynamic來(lái)實(shí)現動(dòng)態(tài)類(lèi)型,在沒(méi)用使用dynamic的地方,C#依然是靜態(tài)的。靜態(tài)類(lèi)型中當我們要使用程序集中的類(lèi),要調用類(lèi)中的方法,編譯器必須知道程序集中有這個(gè)類(lèi),類(lèi)里有這個(gè)方法,如果不能事先知道,編譯時(shí)會(huì )報錯,在C#4以前可以通過(guò)反射來(lái)解決這個(gè)問(wèn)題??匆粋€(gè)使用dynamic的小例子:

dynamic a = "oec2003";
Console.WriteLine(a.Length);//7 
Console.WriteLine(a.length);//string 類(lèi)型不包含length屬性,但編譯不會(huì )報錯,運行時(shí)會(huì )報錯 
Console.ReadLine();

您可能會(huì )發(fā)現使用dynamic聲明變量和C#3中提供的var有點(diǎn)類(lèi)似,其他他們是有本質(zhì)區別的,var聲明的變量在編譯時(shí)會(huì )去推斷出實(shí)際的類(lèi)型,var只是相當于一個(gè)占位符,而dynamic聲明的變量在編譯時(shí)不會(huì )進(jìn)行類(lèi)型檢查。

dynamic用的比較多的應該是替代以前的反射,而且性能有很大提高。假設有一個(gè)名為DynamicLib的程序集中有一個(gè)DynamicClassDemo類(lèi),類(lèi)中有一個(gè)Cal方法,下面看看利用反射怎么訪(fǎng)問(wèn)Cal方法:

namespace DynamicLib
{
    public class DynamicClassDemo 
    {
        public int Cal(int x = 1, int y = 2, int z = 3)
        {
            return (x + y) * z;
        }
    }
}
static void Main()
{
    Assembly assembly = Assembly.Load("DynamicLib");
    object obj = assembly.CreateInstance("DynamicLib.DynamicClassDemo");
    Type type = obj.GetType();
    MethodInfo method = type.GetMethod("Cal");
    Console.WriteLine(method.Invoke(obj, new object[] { 1, 2, 3 }));//9 
    Console.ReadLine();
}

用dynamic的代碼如下:

Assembly assembly = Assembly.Load("DynamicLib");
dynamic obj = assembly.CreateInstance("DynamicLib.DynamicClassDemo");
Console.WriteLine(obj.Cal());
Console.ReadLine();

在前后端分離的模式下,WebAPI接口的參數也可以采用dynamic來(lái)定義,直接就可以解析前端傳入的json參數,不用每一個(gè)接口方法都定義一個(gè)參數類(lèi)型。不好的地方就是通過(guò)Swagger來(lái)生產(chǎn)API文檔時(shí),不能明確的知道輸入參數的每個(gè)屬性的含義。

C#4中還有一些COM互操作性的改進(jìn)和逆變性和協(xié)變性的改進(jìn),我幾乎沒(méi)有用到,所以在此就不講述了。

C#5.0

C# VS版本 CLR版本 .NET Framework
5.0 VS2012\2013 4.0 4.5

異步處理

異步處理是C#5中很重要的一個(gè)特性,會(huì )涉及到兩個(gè)關(guān)鍵字:async和await,要講明白這個(gè)需要單獨寫(xiě)一篇來(lái)介紹。

可以簡(jiǎn)單理解為,當Winform窗體程序中有一個(gè)耗時(shí)操作時(shí),如果是同步操作,窗體在返回結果之前會(huì )卡死,當然在C#5之前的版本中有多種方法可以來(lái)解決這個(gè)問(wèn)題,但C#5的異步處理解決的更優(yōu)雅。

循環(huán)中捕獲變量

與其說(shuō)是一個(gè)特性,不如說(shuō)是對之前版本問(wèn)題的修復,看下面的代碼:

public static void CapturingVariables()
{
    string[] names = { "oec2003","oec2004","oec2005"};
    var actions = new List<Action>();

    foreach(var name in names)
    {
        actions.Add(() => Console.WriteLine(name));
    }
    foreach(Action action in actions)
    {
        action();
    }
}

這段代碼在之前的C#版本中,會(huì )連續輸出三個(gè)oec2005,在C#5中會(huì )按照我們的期望依次輸出oec2003、oec2004、oec2005。

如果您的代碼在之前的版本中有利用到這個(gè)錯誤的結果,那么在升級到C#5或以上版本中就要注意了。

調用者信息特性

我們的程序通常是以release形式發(fā)布,發(fā)布后很難追蹤到代碼執行的具體信息,在C#5中提供了三種特性(Attribute), 允許獲取調用者的當前編譯器的執行文件名、所在行數與方法或屬性名稱(chēng)。代碼如下:

static void Main(string[] args)
{
    ShowInfo();

    Console.ReadLine();

}
public static void ShowInfo(
   [CallerFilePath] string file = null,
   [CallerLineNumber] int number = 0,
   [CallerMemberName] string name = null)
{
    Console.WriteLine($"filepath:{file}");
    Console.WriteLine($"rownumber:{number}");
    Console.WriteLine($"methodname:{name}");
}

調用結果如下:

filepath:/Users/ican_macbookpro/Projects/CsharpFeature/CsharpFeature5/Program.cs
rownumber:12
methodname:Main

C#6.0

C# VS版本 CLR版本 .NET Framework
6.0 VS2015 4.0 4.6

在C#6中提供了不少的新功能,我認為最有用的就是Null條件運算符和字符串嵌入。

Null條件運算符

在C#中,一個(gè)常見(jiàn)的異常就是“未將對象引用到對象的實(shí)例”,原因是對引用對象沒(méi)有做非空判斷導致。在團隊中雖然再三強調,但依然會(huì )在這個(gè)問(wèn)題上栽跟頭。下面的代碼就會(huì )導致這個(gè)錯誤:

class Program
{
static void Main(string[] args)
{
    //Null條件運算符
    User user = null;
    Console.WriteLine(user.GetUserName());
    Console.ReadLine();
}
}
class User
{
public string GetUserName() => "oec2003";
}

要想不出錯,就需要對user對象做非空判斷

if(user!=null)
{
    Console.WriteLine(user.GetUserName()); 
}

在C#6中可以用很簡(jiǎn)單的方式來(lái)處理這個(gè)問(wèn)題

//Null條件運算符
User user = null;
Console.WriteLine(user?.GetUserName()); 

注:雖然這個(gè)語(yǔ)法糖非常簡(jiǎn)單,也很好用,但在使用時(shí)也需要多想一步,當對象為空時(shí),調用其方法返回的值也是空,這樣的值對后續的操作會(huì )不會(huì )有影響,如果有,還是需要做判斷,并做相關(guān)的處理。

字符串嵌入

字符串嵌入可以簡(jiǎn)化字符串的拼接,很直觀(guān)的就可以知道需要表達的意思,在C#6及以上版本中都應該用這種方式來(lái)處理字符串拼接,代碼如下:

//字符串嵌入
string name = "oec2003";
//之前版本的處理方式1
Console.WriteLine("Hello " + name);
//之前版本的處理方式2
Console.WriteLine(string.Format("Hello {0}",name));
//C#6字符串嵌入的處理方式
Console.WriteLine($"Hello {name}");

其他相關(guān)特性

  • 只讀自動(dòng)屬性
  • 自動(dòng)屬性初始化表達式
  • using static
  • nameof表達式
  • 異常篩選器
  • 使用索引器初始化關(guān)聯(lián)集合

C#7.0

C# VS版本 .NET Framework
7.0 VS2017 15.0 .NET Core1.0
7.1 VS2017 15.3 .NET Core2.0
7.2 VS2017 15.5 .NET Core2.0
7.3 VS2017 15.7 .NET Core2.1

out 變量

此特性簡(jiǎn)化了out變量的使用,之前的版本中使用代碼如下:

int result = 0;
int.TryParse("20", out result);
Console.WriteLine(result);

優(yōu)化后的代碼,不需要事先定義一個(gè)變量

int.TryParse("20", out var result);
Console.WriteLine(result);

模式匹配

這也是一個(gè)減少我們編碼的語(yǔ)法糖,直接看代碼吧

public class PatternMatching
{
    public void Test()
    {
        List<Person> list = new List<Person>();
        list.Add(new Man());
        list.Add(new Woman());
        foreach (var item in list)
        {
         //在之前版本中此處需要做類(lèi)型判斷和類(lèi)型轉換
            if (item is Man man)
                Console.WriteLine(man.GetName());
            else if (item is Woman woman)
                Console.WriteLine(woman.GetName());
        }
    }
}
public abstract class Person
{
    public abstract string GetName();
}
public class Man:Person
{
    public override string GetName() => "Man";
}
public class Woman : Person
{
    public override string GetName() => "Woman";
}

詳細參考官方文檔:https://docs.microsoft.com/zh-cn/dotnet/csharp/pattern-matching

本地方法

可以在方法中寫(xiě)內部方法,在方法中有時(shí)需要在多個(gè)代碼邏輯執行相同的處理,之前的做法是在類(lèi)中寫(xiě)私有方法,現在可以讓這個(gè)私有方法寫(xiě)在方法的內部,提高代碼可讀性。

static void LocalMethod()
{
    string name = "oec2003";
    string name1 = "oec2004";

    Console.WriteLine(AddPrefix(name));
    Console.WriteLine(AddPrefix(name1));
    
    string AddPrefix(string n)
    {
        return $"Hello {n}";
    }
}

異步 main 方法

這個(gè)最大的好處是,在控制臺程序中調試異步方法變得很方便。

static async Task Main()
{
    await SomeAsyncMethod();
}

private protected 訪(fǎng)問(wèn)修飾符

可以限制在同一個(gè)程序集中的派生類(lèi)的訪(fǎng)問(wèn),是對protected internal的一種補強,protected internal是指同一程序集中的類(lèi)或派生類(lèi)進(jìn)行訪(fǎng)問(wèn)。

其他相關(guān)特性

  • 元組優(yōu)化(7.0)
  • 棄元(7.0)
  • Ref 局部變量和返回結果(7.0)
  • 通用的異步返回類(lèi)型(7.0)
  • 數字文本語(yǔ)法改進(jìn)(7.0)
  • throw 表達式(7.0)
  • 默認文本表達式(7.1)
  • 推斷元組元素名稱(chēng)(7.1)
  • 非尾隨命名參數(7.2)
  • 數值文字中的前導下劃線(xiàn)(7.2)
  • 條件 ref 表達式(7.2)

總結

每個(gè)特性都需要我們去編碼實(shí)現下,了解了真正的含義和用途,我們才能在工作中靈活的運用。

本文所涉及到的實(shí)例代碼后面也會(huì )上傳到Github上。

希望本文對您有所幫助。

本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
C#基礎溫習: 理解委托和事件
基礎知識---委托和 lambda
一探即將到來(lái)的 C# 10
C#高效編程話(huà)題集2(每期10話(huà)題) - 不如來(lái)編碼-luminji's web - 博客園
C#委托(delegate、Action、Func、predicate)和事件
c#中的委托、事件、Func、Predicate、Observer設計模式以及其他
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久