C#7.0特性

1.Tuples 元组

从一个方法中返回多个值是在实际开发中经常会碰到的场景,一般这种情况我们会使用自定义数据类型、输出参数或者返回一个集合的方式。但在 C# 7.0 中通过元组类型以及元组可以很方便的处理这种场景,请看如下代码:

     

( string, string, string, string) getEmpInfo()
{
    //read EmpInfo from database or any other source and just return them
    string strFirstName = "abc";
    string strAddress = "Address";
    string strCity= "City";
    string strState= "State";
     return (strFirstName, strAddress, strCity, strState); // tuple literal
}

//调用上述方法返回多个值
var empInfo= getEmpInfo();
WriteLine("Emp info as  {empInfo .Item1} {empInfo .Item2} {empInfo .Item3} {empInfo .Item4}.");
Tuples示例

在上述例子中我们可以轻松从元组中返回多个值,但是 Item1, Item2 的名称不好看,我们可以在返回前给它指定一些有意义的名称,如下面代码:

(string strFName, string strAdd, string strC, string strSt) getEmpInfo()
{
    //code goes here
}

//使用指定名称来获取相应值
var empInfo= getEmpInfo();
WriteLine("Emp info as {empInfo.strFName} {empInfo.strAdd} {empInfo.strC} {empInfo.strSt}.");
此外你可以像下面这样直接返回元组中的名称:

return (strFName: strFirstName, strAdd: strAddress, strCity: strC, strState: strSt);

Tuples 元组是非常有用的,可以用来替代哈希表或者字典结构,你设置可以为一个单一的键返回多个值。此外你可以使用它来替代 List 。

.NET 已经有了 Tuple 元组类型 ,但其引用类型会导致一些性能方面的问题。而在 C# 7.0 中提供了值类型的 Tuple 元组,这比老版本速度要快很多,同时还提供了可变类型。

析构

绝大多数时候我们不会去访问整个 Tuple 元组,或者说我们只需要内部的一些值,这个时候我们就可以用 C# 7.0 的 Deconstruction 析构特性,通过它轻松释放一个元组或者从中获取所需的值,请看如下代码:

( string strFName,  string strAdd,  string strC, string strSt) = getEmpInfo(); 
Console.WriteLine($"Address: { strAdd }, Country: { strC }");

2.记录类型 Record Type

C# 支持 Record Type 记录类型,其实说白了就是属性和值的容器。绝大多数类是包含属性和值的,我们需要大量的代码来声明这种类型。有了 Record Type 之后就可以大量减少代码,如下代码片段所示:

class studentInfo
{
    string _strFName;
    string _strMName;
    string _strLName;
    studentInfo(string strFN, string strMN, string strLN){
        this._strFName = strFN;
        this._strMName = strMN;
        this._strLName = strLN;
    }
    public string StudentFName {get{ return this._strFName;}}
    public string StudentMName {get{ return this._strMName;}}
    public string StudentLName {get{ return this._strLName;}}

上述代码中我们定义了一个包含属性、构造函数和变量的类,为了访问和声明变量我需要编写更多的代码。

C# 7.0 的 Record Type 可以避免这种情况,请看代码:

class studentInfo(string StudentFName, string StudentMName, string StudentLName);

3.最小化 OUT 输出变量

当我们需要一个方法返回多个值的时候,经常会用到输出参数。但是一般输出参数是引用类型,而且它其实就是一个参数,这样使用只不过是受限于语言本身的限制,不过有一个限制就是输出参数在使用前必须被初始化,如下代码所示:

class SetOut
{
    void AssignVal(out string strName)
    {
        strName = "I am from OUT";
    }
    static void Main()
    {
        string strArgu;
        AssignVal(out strArgu);
        // here contents of strArgu is "I am from OUT"
    }
}

C# 7.0 减少了编写额外代码的痛苦,你不需要在传递参数前进行初始化,如下所示:

 static void Main()
    {
        AssignVal(out string szArgu);
        // here contents of szArgu is "I am from OUT"
    }

可以使用 var 作为参数类型,这样就不需要使用前进行声明。

注意在这里使用的这些变量只在一个受限的范围内有效,因此我们不能在方法外使用这些变量。

一旦我们将变量直接作为参数使用,C# 7.0 可以通过 var 关键字来进行声明。因此你不用担心数据类型问题,请看下面代码:

static void Main()
{
   AssignVal(out var szArgu);
   // here contents of szArgu is "I am from OUT"
}

4.不允许为空的引用类型

'?' 用于允许为空的值类型,而 '!' 是不允许为空的引用类型。

int objNullVal;     //non-nullable value type
int? objNotNullVal;    //nullable value type
string! objNotNullRef; //non-nullable reference type
string objNullRef;  //nullable reference type
现在再来看看在运行这个代码之后的编译器效果

MyClass objNullRef;  // Nullable reference type
MyClass! objNotNullRef; // Non-nullable reference type
 
objNullRef = null;   // this is nullable, so no problem in assigning
objNotNullRef = null;   // Error, as objNotNullRef is non-nullable
objNotNullRef = objNullRef;      // Error, as nullable object can not be refered
 
WriteLine(objNotNullRef.ToString()); // Not null so can convert to tostring
WriteLine(objNullRef.ToString()); // could be null
 
if (objNullRef != null) { WriteLine(objNullRef.ToString); } // No error as we have already checked it
WriteLine(objNullRef!.Length); // No error

5.本地方法和函数

在当前的 C# 版本中已经有本地方法和函数(请看 Func  和 Action), 但对于本地方法仍有一些限制,例如不能使用如下特性:

  • 泛型
  • 输出参数
  • Ref
  • params

而现在 C# 7.0 就解决了这些问题,请看下面代码:

private static void Main(string[] args)
{
    int local_var = 100;
    int LocalFunction(int arg1)
    {
        return local_var * arg1;
    }
 
    Console.WriteLine(LocalFunction(100));
}

6.代码可读性的提升

我们经常在代码中使用字面量,如果这些字面量太长就会影响可读性。因此 C# 7.0 在这方面做了改进。C# 7.0 允许使用 '_' 下划线以便于更好的理解,如下代码所示:

var lit1 = 478_1254_3698_44;
 var lit2 = ab0Xab_bc47at_XY;

//C# also come with binary literal for bunary values

 var binLit = 1100_1011_0100_1010_1001;

7.模式匹配

C# 7.0 允许用户在 IS 和 SWITCH 语句中使用模式匹配,因此我们可以匹配任意的数据类型,模式可以是常亮模式,类型模式以及 Var 模式。下面的代码将有助于你理解这个概念,让我们从 IS 模式开始:

 public  void Method1( object obj)
{
    //following null is constant pattern
     if (obj  is null)  return;
    //datatype pattern, string is datatype that we check directly     
     if (obj  is  string st)
    { //code goes here }
    else
    return; 
}

Switch 模式 可以通过额外的 case 语句在使用任意类型的数据匹配实现更多的帮助和更灵活的方式。

class Calculate();
class Add(int a, int b, int c) : Calculate;
class Substract(int a, int b) : Calculate;
class Multiply(int a, int b, int c) : Calculate;
 
Calculate objCal = new Multiply(2, 3, 4);
switch (objCal)
{
    case Add(int a, int b, int c):
        //code goes here
        break;
    case Substract(int a, int b):
        //code goes here
        break;
    case Multiply(int a, int b, int c):
        //code goes here
        break;
    default:
        //default case
        break;
}

8.通过 Ref 返回 'return'

你是否尝试过在方法中返回变量的引用?C# 7.0 就允许你这样做。你可以传递一个使用 Ref 声明的变量并作为 Ref 返回,也可以作为 Ref 存储,是不是很神奇?

来看代码:

ref string getFromList(string strVal, string[] Values)
{
 foreach (string val1 in Values)
 {
     if (strVal == val1)
        return ref val1; //return location as ref not actual value
 }
}

string[] values = { "a", "b", "c", "d" };
ref string strSubstitute = ref getFromList("b", values);
strSubstitute = "K"; // replaces 7 with 9 in the array
System.Write(values[1]); // it prints "K"

9.表达式可以抛出异常

public string getEmpInfo( string EmpName)
    {
        string[] empArr = EmpName.Split(",");
        return (empArr.Length > 0) ? empArr[0] : throw new Exception("Emp Info Not exist");
    }

 

posted @ 2017-02-28 16:03  聆听的风声  阅读(135)  评论(0)    收藏  举报