总目录
C# 语法总目录
C# 语法中级
lambda 表达式
编译器在内部将lambda表达式编译为一个私有方法,并将表达式代码转移到该方法中。
1. 捕获外部变量
lambda表达式可以引用方法内定义的局部变量和方法的参数
捕获的变量在真正调用委托时赋值,而不是在捕获时赋值
static void Main(string[] args)
{
int num = 2;
Func<int, int> multi = n => n * num;
Console.WriteLine(multi(3)); //6
num = 10;
//调用时才给捕获变量赋值
Console.WriteLine(multi(3)); //30
}
2. 捕获迭代变量
捕获迭代变量时因为捕获的是同一个变量,值变,地址却没变。又有捕获变量是调用时才赋值,所以在迭代完成后,输出的都是一样的值。
Action[] actions = new Action[3];
for (int i = 0; i < actions.Length; i++)
{
actions[i] = () => Console.Write(i);
}
foreach (Action a in actions)
{
a();
}
//输出 333
//如果想获取迭代时的值,那么有这么几种方式
//方式1 获取后立马调用
Action[] actions = new Action[3];
for (int i = 0; i < actions.Length; i++)
{
actions[i] = () => Console.Write(i);
actions[i](); //输出012
}
//方式2 使用局部变量,保存的每个值地址都不一样,不是同一个变量
Action[] actions = new Action[3];
for (int i = 0; i < actions.Length; i++)
{
//局部变量
int num = i;
actions[i] = () => Console.Write(num);
}
foreach (Action a in actions)
{
a(); //输出 012
}
匿名类型
var person = new {Name="lisi",Age=18};
//或者
int age = 18;
var person = new {Name="lisi",Age = age};
var person1 = new {Name="zhangsan",Age = "20"};
Console.WriteLine(person.GetType()==person1.GetType()); //True
匿名方法
匿名方法
delegate int Transformer(int i);
static void Main(string[] args)
{
Transformer sqr = delegate (int x) { return x * x; };
Console.WriteLine(sqr(3));
Console.ReadLine();
}
//9
异常相关
常见异常
System.ArgumentException; //参数异常
System.ArgumentNullException; //空参数异常
System.ArgumentOutOfRangeException; //参数超过范围
System.InvalidOperationException; //方法执行失败
System.NotSupportedException; //不支持特定的功能异常
System.NotImplementedException; //未实现异常
System.NullReferenceException; //空参数异常
try…catch…finally语句
try
{
}
catch (Exception e)
{
}
finally
{
}
枚举器和迭代器
1. 枚举器
枚举器(Enumerator)是一个只读的且只能在值序列上前移的游标。
任何具有MoveNext方法和Current属性的对象都被称作枚举器。
枚举器实现了下面的接口之一:
-
System.Collections.IEnumerator
-
System.Collections.Generic.IEnumerator
2. 可枚举对象
可枚举对象(Enumerable),它可以生成枚举器。
可枚举的对象可以是:
-
IEnumerable 或 IEnumerable的实现。
-
具有名为GetEnumerator 的方法并且返回值是一个枚举器 (Enumerator)对象
注意:IEnumerator 和 IEnumerable 定义在 System.Collections 里。
IEnumerator 和 IEnumerable 定义在 System.Collections.Generic 里。
//枚举器模板
class Enumerator
{
public IteratorVariableType Current{ get{...}}
public bool MoveNext(){...}
}
//可枚举类型模版
class Enumerable
{
public Enumerator GetEnumerator(){...}
}
3. 迭代器
迭代器是枚举器的生产者。foreach语句是枚举器的消费者。
案例:使用迭代器来返回斐波那契数列(每个数字是前两个数字之和)
using System;
using System.Collections.Generic;
class Test
{
static void Main()
{
foreach(int fib in Fibs(6))
Console.Write(fib+" ");
}
//迭代器方法
static IEnumerable<int> Fibs(int fibCount)
{
for(int i =0,prevFib =1,curFib=1;i<fibCount;i++)
{
yield return prevFib;
int newFib = prevFib+curFib;
prevFib = curFib;
curFib = newFib;
}
}
}
//输出
1 1 2 3 5 8
3. 迭代器语义
迭代器是包含一个或者多个 yield 语句的方法,属性或者索引器。
//迭代器必须返回以下四个接口之一(否则编译器会产生相应错误):
//可枚举接口
System.Collections.IEnumerable
System.Collections.Generic.IEnumerable<T>
//枚举器接口
System.Collections.IEnumerator
System.Collections.Generic.IEnumerator<T>
//多个yield语句
class Test
{
static void Main()
{
foreach(string s in Foo())
Console.WriteLine(s); //输出 One,Two,Three
}
static IEnumerable<string> Foo()
{
yield return "One";
yield return "Two";
yield return "Three";
}
}
4. yield break 语句
yield break 语句表明迭代器块不再返回更多的元素,而是提前退出。
static IEnumerable<string> Foo(bool breakEarly)
{
yield return "One";
yield return "Two";
if(breakEarly)
yield break; //到这里就退出了
yield return "Three";
}
注意:yield return 语句不能出现在 try…catch…finally 块中,只能出现在try…finally中try块里面。
通常使用foreach或隐式销毁枚举器,但是如果显示使用枚举器,提前结束枚举而不销毁枚举器,绕过了finally块的执行。那么我们可以将枚举器显式包裹在using语句中来避免上述错误。
string firstElement = null;
var sequence = Foo();
using(var enumerator = sequence.GetEnumerator()) //使用using,会自动关闭一个持续流
if(enumerator.MoveNext())
firstElement = enumerator.Current;
5. 组合序列
迭代器有高度可组合性。迭代器模式的组合对LINQ非常重要。
class Program
{
static void Main(string[] args)
{
foreach (int fib in EvenNumbersOnly(Fibs(6)))
{
Console.WriteLine(fib);
}
}
static IEnumerable<int> Fibs(int fibCount)
{
for (int i = 0,prevFib = 1,curFib =1; i<fibCount; i++)
{
yield return prevFib;
int newFib = prevFib + curFib;
prevFib = curFib;
curFib = newFib;
}
}
static IEnumerable<int> EvenNumbersOnly(IEnumerable<int> sequence)
{
foreach (int x in sequence)
{
if ((x % 2) ==0)
{
yield return x;
}
}
}
}
可空类型
可空类型必须要在数据类型后加一个 ? 表示
string s = null; //不报错,引用类型可以为null
int i = null; //报错,值类型不能为null
//如果想要一个值类型表示null,那么必须要用可空类型
//可空类型是由数据类型后加一个?来表示
int? i = null;
Console.WriteLine(i==null); //输出 True
1. Nullable< T > 结构体
上面案例中的 int? 会被编译为 System.Nullable< T >,它是一个轻量级的不可变的结构体。它只有两个字段,分别代表Value和HasValue。
public struct Nullable<T> where T : struct
{
public T Value {get;}
public bool HasValue {get;}
public T GetValueOrDefault();
public T GetValueOrDefault(T defaultValue);
...
}
//因此
int? i =null;
Console.WriteLine(i == null); //True
//等价于
Nullable<int> i = new Nullable<int>();
Console.WriteLine(!i.HasValue); //True
标签:中级,Console,迭代,C#,System,yield,语法,int,枚举 From: https://blog.csdn.net/qq_44653106/article/details/137838689总目录
C# 语法总目录