C# 7.0 的新特性






4.34/5 (49投票s)
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 类型来实现它们,请参阅 Func 和 Action),但局部方法仍然存在一些限制,我们无法在其中获得以下特性:
- 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' 作为局部函数,在这里我们可以使用out 或ref。
通过字面量提高可读性
很多时候我们在代码中使用字面量,如果它们太长,我们可能会失去可读性。为了解决这些问题,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 的这些新特性!
- 编码愉快