You do not know the details of C #

Original: You do not know the details in C #

Preface #

There is a thing called duck type, the so-called duck typing is that as long as things behave like a duck then be able to launch this thing is a duck.

C # is actually hidden inside a lot of similar types of ducks, but many developers do not know and, therefore, can not make use of these things, so today I'm hidden in the breakdown of what these compilers in detail.

Not only Taskand ValueTaskto await#

When writing asynchronous code in C #, we often choose asynchronous code is contained in one Taskor ValueTask, the caller will be able to use this awaitway to achieve an asynchronous call.

Xika Xi, is not the only Taskand ValueTaskability await. TaskAnd ValueTaskbehind the thread pool is obviously involved in scheduling, but why the C # async/ awaitwas said to be coroutineit?

Because you awaitare not necessarily things Task/ ValueTask, in C # as long as your class contains GetAwaiter()methods and bool IsCompletedproperties, and GetAwaiter()things returned contains a GetResult()method, a bool IsCompletedproperty and implemented INotifyCompletion, the object of this class is that you can awaitof.

Therefore, in the package I / O operations, we can achieve a self Awaiter, which is based on the underlying epoll/ IOCPimplementation, so that when awaitthe time does not create any threads, also without any thread scheduling, but to directly Control. The OS after the completion of I / O by calling CompletionPort(Windows), etc. to inform the user mode to complete an asynchronous call, then resume the context continue with the remaining logic, which is actually a real stackless coroutine.

 
 
Copy
public class MyTask<T> { public MyAwaiter<T> GetAwaiter() { return new MyAwaiter<T>(); } } public class MyAwaiter<T> : INotifyCompletion { public bool IsCompleted { get; private set; } public T GetResult() { throw new NotImplementedException(); } public void OnCompleted(Action continuation) { throw new NotImplementedException(); } } public class Program { static async Task Main(string[] args) { var obj = new MyTask<int>(); await obj; } }

In fact, the .NET Core I / O associated with asynchronous API is indeed doing so, the process I / O operation will not have any thread waiting for the results of the allocation are coroutineoperating: the direct I / O operations begin let out of control until the I / O operation is complete. The reason that sometimes you find awaitbefore and after the thread has changed, it is only because Taskitself is scheduled.

UWP used in the development of IAsyncAction/ IAsyncOperation<T>is from the bottom of the package, and Taskhas nothing to do but can await, and if the C ++ / WinRT development UWP then return these interfaces are also possible methods co_awaitof.

Not only IEnumerableand IEnumeratorin order to be foreach#

We will often write the following code:

 
 
Copy
foreach (var i in list) { // ...... }

Then one can ask why foreach, because most of them will reply that listimplements IEnumerableor IEnumerator.

But in fact, if you want to be an object foreach, only you need to provide a GetEnumerator()method, and the GetEnumerator()returned object contains a bool MoveNext()add a method Currentattribute.

 
 
Copy
class MyEnumerator<T> { public T Current { get; private set; } public bool MoveNext() { throw new NotImplementedException(); } } class MyEnumerable<T> { public MyEnumerator<T> GetEnumerator() { throw new NotImplementedException(); } } class Program { public static void Main() { var x = new MyEnumerable<int>(); foreach (var i in x) { // ...... } } }

Not only IAsyncEnumerableand IAsyncEnumeratorin order to be await foreach#

As above, but this time the requirements have changed, GetEnumerator()and MoveNext()changed GetAsyncEnumerator()and MoveNextAsync().

In which MoveNextAsync()things should be a return Awaitable<bool>, as this Awaitablewhat in the end is that it can be Task/ ValueTaskmay be other or your own implementation.

 
 
Copy
class MyAsyncEnumerator<T> { public T Current { get; private set; } public MyTask<bool> MoveNextAsync() { throw new NotImplementedException(); } } class MyAsyncEnumerable<T> { public MyAsyncEnumerator<T> GetAsyncEnumerator() { throw new NotImplementedException(); } } class Program { public static async Task Main() { var x = new MyAsyncEnumerable<int>(); await foreach (var i in x) { // ...... } } }

ref structHow to achieve IDisposable#

As we all know ref structbecause it is necessary and can not be boxed in on the stack, it can not implement the interface, but if you ref structhave a void Dispose()so it can be used usingto achieve the object syntax is automatically destroyed.

 
 
Copy
ref struct MyDisposable { public void Dispose() => throw new NotImplementedException(); } class Program { public static void Main() { using var y = new MyDisposable(); // ...... } }

Not only Rangecan use slices #

C # 8 introduces Ranges, allowing the slicing operation, but in fact is not necessary to provide a receiving Rangeindexer can type parameters to use this feature.

As long as your class can be counted (owned Lengthor Countattributes), and may be sliced (to have a Slice(int, int)method), then you can use this feature.

 
 
Copy
class MyRange { public int Count { get; private set; } public object Slice(int x, int y) => throw new NotImplementedException(); } class Program { public static void Main() { var x = new MyRange(); var y = x[1..]; } }

Not only Indexcan use the index #

C # 8 Indexes for the introduction of the index, such as the use of ^1the index penultimate element, but is actually not necessary to provide a receiving Indexindexer can type parameters to use this feature.

As long as your class can be counted (owned Lengthor Countattributes) and may be indexed (has a receiver intindexer parameters), then you can use this feature.

 
 
Copy
class MyIndex { public int Count { get; private set; } public object this[int index] { get => throw new NotImplementedException(); } } class Program { public static void Main() { var x = new MyIndex(); var y = x[^1]; } }

To achieve the type of deconstruction #

How to achieve a type of deconstruction of it? In fact, just write a name for Deconstruct()the method, and the parameters are outcan be.

 
 
Copy
class MyDeconstruct { private int A => 1; private int B => 2; public void Deconstruct(out int a, out int b) { a = A; b = B; } } class Program { public static void Main() { var x = new MyDeconstruct(); var (o, u) = x; } }

Not only realized IEnumerablein order to use LINQ#

LINQ C # is commonly used in an integrated query language allows you to write code like this:

 
 
Copy
from c in list where c.Id > 5 select c;

However, in the above code listtypes do not necessarily have to realize IEnumerable, in fact, as long as there is a corresponding name extension methods can be, for example, has called the Selectmethod can be used select, with the known Wheremethods can be used where.

 
 
Copy
class Just<T> : Maybe<T> { private readonly T value; public Just(T value) { this.value = value; } public override Maybe<U> Select<U>(Func<T, Maybe<U>> f) => f(value); public override string ToString() => $"Just {value}"; } class Nothing<T> : Maybe<T> { public override Maybe<U> Select<U>(Func<T, Maybe<U>> _) => new Nothing<U>(); public override string ToString() => "Nothing"; } abstract class Maybe<T> { public abstract Maybe<U> Select<U>(Func<T, Maybe<U>> f); public Maybe<V> SelectMany<U, V>(Func<T, Maybe<U>> k, Func<T, U, V> s) => Select(x => k(x).Select(y => new Just<V>(s(x, y)))); public Maybe<U> Where(Func<Maybe<T>, bool> f) => f(this) ? this : new Nothing<T>(); } class Program { public static void Main() { var x = new Just<int>(3); var y = new Just<int>(7); var z = new Nothing<int>(); var u = from x0 in x from y0 in y select x0 + y0; var v = from x0 in x from z0 in z select x0 + z0; var just = from c in x where true select c; var nothing = from c in x where false select c; } }

Guess you like

Origin www.cnblogs.com/lonelyxmas/p/12630097.html