C# 冷知识(一)

143 阅读2分钟

函数传参

位置参数

最常用的使用

void Foo(string name,int age,bool active)
{
    
}

Foo("Tom", 18, true);

命名参数

常用于某个参数已指定默认值,使用命名参数后可以跳过某些参数,对后面的进行传毒

void Foo(string name,int age = 18,bool active = true)
{

}

Foo("Tom", active:true);

位置参数 + 命名参数

void Foo(string name,int age = 18,bool active = true)
{

}

Foo("Tom", age:11 , false);

枚举类型的数据格式化

默认枚举项存储的实际为一个个int值

enum Colors
{
    Red,
    Green, 
    Blue
}

可以通过继承类型类,从而存储其他类型数据

enum Colors:byte
{
    Red=0x01,
    Green,
    Blue
}

显示实现接口方法

默认某个类继承了一个接口,就要实现该接口的所有方法

interface IFoo
{
    void Foo();
}

class MyClass : IFoo
{
    public void Foo()
    {
      Console.WriteLine("hi");
    }
}

但是可以使用显示实现接口,隐藏实现过程

interface IFoo
{
    void Foo();
}

class MyClass : IFoo
{
    void IFoo.Foo()
    {
        Console.WriteLine("hi");
    }
}

只有强制类型转化后,才可调用实现的方法

var mc = new MyClass();
((IFoo)mc).Foo();

可等待

一般想要暂停1秒后再运行,可使用 async + await 组合使用

await FooAsync();

async Task FooAsync()
{
    await Task.Delay(1000);
}

此外,任何一个实现了GetAwaiter的类,都可以进行await操作

using System.Runtime.CompilerServices;

var md = new MyDelay(2);
await md;

class MyDelay
{
    int seconds;
    public MyDelay(int seconds)
    {
        this.seconds = seconds;
    }
    public TaskAwaiter GetAwaiter()
    {
        return Task.Delay(TimeSpan.FromSeconds(seconds)).GetAwaiter();
    }

}

上述类还可以进行拓展:

using System.Runtime.CompilerServices;

var md = new MyDelay(2);
await md;

class MyDelay
{
    public int seconds { get; private set; }
    public MyDelay(int seconds)
    {
        this.seconds = seconds;
    }

}

static class MyExtensions
{
    public static TaskAwaiter GetAwaiter(this MyDelay md)
    {
        return Task.Delay(TimeSpan.FromSeconds(md.seconds)).GetAwaiter();
    }
}

又或者是:

using System.Runtime.CompilerServices;

await TimeSpan.FromSeconds(2);

class MyDelay
{
    public int seconds { get; private set; }
    public MyDelay(int seconds)
    {
        this.seconds = seconds;
    }

}

static class MyExtensions
{
    public static TaskAwaiter GetAwaiter(this TimeSpan ts)
        => Task.Delay(ts).GetAwaiter();
}

甚至可以更简洁为:

using System.Runtime.CompilerServices;

await 2;

class MyDelay
{
    public int seconds { get; private set; }
    public MyDelay(int seconds)
    {
        this.seconds = seconds;
    }

}

static class MyExtensions
{
    public static TaskAwaiter GetAwaiter(this int seconds)
        => Task.Delay(TimeSpan.FromSeconds(seconds)).GetAwaiter();
}

可枚举

已知:如果一个类实现了IEnumerabl接口,那么就可以进行foreach操作

using System.Collections;

var mc = new MyClass();
foreach(var item in mc)
{
    Console.WriteLine(item);
}

class MyClass: IEnumerable
{
    public IEnumerator GetEnumerator()
    {
        for (int i = 0; i < 10; i++)
        {
            yield return i.ToString();
        }
    }

}

实际上不用继承IEnumerabl接口,仅仅实现GetEnumerator方法即可进行调用foreach

using System.Collections;

var mc = new MyClass();
foreach(var item in mc)
{
    Console.WriteLine(item);
}

class MyClass
{
    public IEnumerator GetEnumerator()
    {
        for (int i = 0; i < 10; i++)
        {
            yield return i.ToString();
        }
    }

}

同理,可拓展为:

using System.Collections;

var mc = new MyClass();
foreach(var item in 5)
{
    Console.WriteLine(item);
}

class MyClass
{

}

static class MyExtensions
{
    public static IEnumerator GetEnumerator(this int count)
    {
        for (int i = 0; i < count; i++)
        {
            yield return i.ToString();
        }
    }
}

异步可枚举

上述方法也提供了异步操作:

var mc = new MyClass();
await foreach(var item in mc)
{
    Console.WriteLine(item);
}

class MyClass : IAsyncEnumerable<int>
{
    public async IAsyncEnumerator<int> GetAsyncEnumerator(CancellationToken cancellationToken = default)
    {
        for (int i = 0; i < 10; i++)
        {
            await Task.Delay(200);
            yield return i;
        }
    }
}

序号与范围

若想输出数组最后一个元素:

var arr = new[] { 1, 2, 3, 4 };
int v1 = arr[arr.Length - 1];
int v2 = arr[^1];

若想访问中间几个元素:

var arr = new[] { 1, 2, 3, 4 ,5,6};
int[] ints = arr[1..4];

数字可读性

long bigNumber = 10_000_000;