C#里 =>的用法


問題

看到有人寫這樣的代碼,這里的=>讓人感到疑惑,我一直以為它是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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM