問題
看到有人寫這樣的代碼,這里的=>讓人感到疑惑,我一直以為它是Lambda表達式的寫法,跟C++的->
類似,比較好理解,但是明顯下面這里的代碼不是屬於Lambda表達式的范圍
// 這里的MaxHealth1和MaxHealth2有什么區別?
public class Health
{
// expression-bodied member property
public int MaxHealth1 => x ? y:z;
// field with field initializer
public int MaxHealth2 = x ? y:z;
};
為了解決這個問題,寫下了這篇博客
C#里=>的兩種用法
C#里的=>
有兩種用法:
- 用於Lambda表達式里,此時的
=>
被稱為lambda operator - 用於expression-bodied member
第一種用法
第一種用法,比較好理解,其實就是Lambda表達式的寫法,在C# 3到C# 5版本間,=>
只有此種用法。此時的=>
C++的lambda表達式里的->
類似,舉個例子:
// 聲明一個函數指針的對象, 也就是委托, 其函數簽名為string f(Person)
Func<Person, string> nameProjection = p => p.Name;
// 上面這句, 等同於:
Func<Person, string> nameProjection = delegate (Person p) { return p.Name; };
注意這里的Func<T, TResult>
,最后面的代表函數的返回類型,前面的代表函數的參數,Func只是.NET提供的委托模板:
namespace System
{
// Summary:
// Encapsulates a method that has one parameter and returns a value of the type
public delegate TResult Func<in T, out TResult>(T arg);
}
第二種用法
在C# 6的版本里,=>
開始用於expression-bodied members,代碼如下:
public int MaxHealth1 => x ? y:z;
而這種語法,是一種Syntax Sugar,上面的代碼等同於下面的:
public int MaxHealth1
{
get
{
return x ? y:z;
}
}
所以,上面的MathHealth1和MathHealth2的區別,其實就是C#里Property和Field的區別:
- MaxHealth1是一個Property,設置了getter,每次訪問該值的時候,都會調用x?y:z表達式
- MathHeath2是一個Field,它的表達式只會在其初始化時計算一次
其實應該說的很清楚了,再舉個例子:
class Program
{
public class A
{
public static int x;//默認初始化為0
public int X1 => x;
public int X2 = x;
}
static void Main()
{
Console.WriteLine(A.x);// 0
A a = new A();
Console.WriteLine(a.X1);// 0
Console.WriteLine(a.X2);// 0
A.x = 5;
Console.WriteLine(a.X1);// 5
Console.WriteLine(a.X2);// 0
A.x = 10;
Console.WriteLine(a.X1);// 10
Console.WriteLine(a.X2);// 0
}
}
可以看到,每次去取X1的值的時候,都會執行return x;
這個表達式,所以上面的問題解決了。
參考資料:
https://stackoverflow.com/questions/290061/what-does-the-syntax-in-c-sharp-mean/290063#290063
https://stackoverflow.com/questions/31764532/what-is-the-assignment-in-c-sharp-in-a-property-signature
一個小問題
寫這個類的時候,編譯報了錯:
public class A
{
public int x;//默認初始化為0
public int X1 => x;//這一句是OK的
public int X2 = x;// 這一句編譯報錯
}
報錯的信息如下:
A field initializer cannot reference the nonstatic field, method, or property
意思是,一個類里的field不可以用非static的field、method或property進行初始化,也就是說類里field要用靜態成員或函數才可以為其初始化。
原因是,在C#里規定,不可以用一個instance variable作為另外一個instance varialble的初始值,因為這里無法保證哪一個變量是先初始化的。
順便提一句,有意思的是,在C++里,類似的代碼是可以運行的,因為C++里類的成員變量是按照聲明順序進行初始化的,代碼如下:
#include <iostream>
class T
{
public:
int c = a;// 可以成功編譯和運行
int a = 3;
int b = a;
};
int main()
{
T t;
std::cout << t.a << std::endl;// 3
std::cout << t.b << std::endl;// 3
std::cout << t.c << std::endl;// undefined
std::cin.get();
}
C#的Property和Field
之前看過書做過記錄,這里復制粘貼一下:
在C++中,為了安全,對於一個類的數據成員,往往是將其設置為private,然后使用對於的Get和Set功能的API去調用和寫入值,在C#中,可以通過Field和Property來實現對應的功能,用一句最簡單的話就是,Properties expose fields,Property是field的接口,如下述代碼所示:
public class MyClass
{
// this is a field. It is private to your class and stores the actual data.
private string _myField;
// this is a property. When accessed it uses the underlying field,
// but only exposes the contract, which will not be affected by the underlying field
public string MyProperty
{
get
{
return _myField;
}
set
{
_myField = value;
}
}
// This is an AutoProperty (C# 3.0 and higher) - which is a shorthand syntax
// used to generate a private field for you
public int AnotherProperty{get;set;}
}
注意:field成員一般(或者說總是)被聲明為private,C#3.0以后支持只寫Property而不用在類里再寫一個private的field,會自動生成對應的field
更多詳情可以參考StackOverflow