65.9K
CodeProject 正在变化。 阅读更多。
Home

C# 7.0 的新特性

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.34/5 (49投票s)

2016年10月6日

CPOL

5分钟阅读

viewsIcon

144481

C# 7.0 中引入的新特性列表

引言

C# 7.0 计划分批发布,微软已通过 Visual Studio “15” Preview 4 发布了大部分特性,该版本已于上个月(2016 年 8 月)发布。请参阅 发布博文

代码简化和性能改进是此版本的主要核心。元组(Tuples)、模式匹配(Pattern matching)是一些引入的非常好的特性。希望您会喜欢这些特性,并提高工作效率。

 让我们来看看 C# 7.0 的新特性

使用代码

元组(Tuples)(带类型和字面量)

从方法返回多个值现在已是常见做法,我们通常使用自定义数据类型、out 参数、动态返回类型或元组对象,但 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
}

//Just call above method and it will return multiple values 
 var empInfo= getEmpInfo();
WriteLine("Emp info as  {empInfo .Item1} {empInfo .Item2} {empInfo .Item3} {empInfo .Item4}.");

在上面的示例中,我们可以轻松地从元组中检索多个值,但 Item1、Item2 的名称有点不相关,所以我们在返回之前给它们起一个有意义的名称,请看下面的示例:

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

//Now when you call method get values with specific name as below 
var empInfo= getEmpInfo();
WriteLine("Emp info as {empInfo.strFName} {empInfo.strAdd} {empInfo.strC} {empInfo.strSt}.");

此外,您可以在元组字面量中直接返回它们的名称,如下所示:

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

元组是非常有用的东西,您可以用它轻松替换哈希表或字典,甚至可以为一个键返回多个值。此外,当您在单个位置存储多个值时,可以使用它代替 List。

.NET 也有一个 Tuple 类型(参见此处),但它是一个引用类型,这会导致性能问题。但 C# 7.0 带来了值类型的 Tuple,其性能更快,并且是可变类型。

解构(Deconstruction)

大多数时候我们不希望访问整个元组包,或者我们只需要内部值,那么我们可以使用 C# 7.0 的解构特性,我们可以轻松地解构一个元组并获取所需的值,下面的代码片段将澄清您的疑问:

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

记录类型(Record Type)

C# 支持记录类型,它不过是属性和变量的容器。大多数时候类充满了属性和变量,我们需要大量代码来声明它们,但借助记录类型,您可以减少工作量,请看下面的代码片段:

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# 中使用记录类型,请看下面的代码片段:

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

就是这样,我们完成了!

上面的代码片段产生了与先前代码片段相同的输出。

 

最小化 OUT 参数

Out 参数在我们希望从方法返回多个值时非常受欢迎。Out 参数的本质是 ref 类型,并作为参数工作。我们可以轻松地使用它,但唯一的条件是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 减少了您编写额外代码的麻烦,您可以直接传递参数而无需初始化它们,请看下面的代码片段:

pat

  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"
    }

 

非空引用类型(Non-'NULL' able reference type)

空引用对所有程序员来说都是一个很大的麻烦,这是一个价值百万的异常。如果您不检查它们,您将遇到运行时异常;如果您为每个对象都检查它们,您的代码会变得冗长。为了解决这个问题,C# 7.0 提供了非空引用类型。

**我认为它的语法尚未固定,但他们已发布了以下语法:

'?' 用于可空值类型,'!' 用于非空引用类型。

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

 

局部方法/函数(Local Methods/Functions)

 

局部方法和函数已经存在于当前版本的 C# 中(是的,我们可以使用 Func 和 Action 类型来实现它们,请参阅 FuncAction),但局部方法仍然存在一些限制,我们无法在其中获得以下特性:

  • Generic
  • out 参数
  • 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));
}

在上面的代码片段中,我们在 Main 函数 'Main' 中定义了 'LocalFunction' 作为局部函数,在这里我们可以使用outref

通过字面量提高可读性

很多时候我们在代码中使用字面量,如果它们太长,我们可能会失去可读性。为了解决这些问题,C# 7.0 在字面量方面进行了一些改进。现在 C# 允许在字面量中使用'_'(下划线)以提高可理解性,它不会影响其值。请看下面的代码片段:

 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;

**字面量不过是一个常量值(硬编码值),它可能有预定义的含义。(C# 中的字面量

模式匹配

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;
}

在上面的示例中,switch case 检查模式并调用 'Multiply' 方法。

通过 Ref 返回

您是否尝试过将变量作为 Ref 从方法/函数返回?是的,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"

在上面的示例中,我们通过从方法返回 Ref 来查找和替换一个字符串。

从表达式抛出异常

您没看错,在 C# 7.0 中,您现在可以直接从表达式中抛出异常。请看下面的代码片段:

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

在上面的代码片段中,我们可以直接从return 语句中抛出异常,这真的很棒!

需要注意的点

以上所有特性预计都将成为 C# 7.0 的一部分,尽管微软已在Visual Studio 2015 Release 4 中发布了其中一些。

希望您喜欢 C# 7.0 的这些新特性!

- 编码愉快

 

© . All rights reserved.