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,最后面的代表函数的返回类型,前面的代表函数的参数,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 

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

你可能感兴趣的:(C#语言)