温州专业微网站制作多少钱,东莞建设网站的位置,佛山网站建设永网,吕梁网站制作解析“60k”大佬的19道C#面试题#xff08;上#xff09;先略看题目#xff1a;请简述 async函数的编译方式请简述 Task状态机的实现和工作机制请简述 await的作用和原理#xff0c;并说明和 GetResult()有什么区别Task和 Thread有区别吗#xff1f;如果有请简述区别简述 … 解析“60k”大佬的19道C#面试题上先略看题目请简述 async函数的编译方式请简述 Task状态机的实现和工作机制请简述 await的作用和原理并说明和 GetResult()有什么区别Task和 Thread有区别吗如果有请简述区别简述 yield的作用利用 IEnumerableT实现斐波那契数列生成简述 stackless coroutine和 stackful coroutine的区别并指出 C#的 coroutine是哪一种请简述 SelectMany的作用请实现一个函数 Compose用于将多个函数复合实现 MaybeT monad并利用 LINQ实现对 Nothing空值和 Just有值的求和简述 LINQ的 lazy computation机制利用 SelectMany实现两个数组中元素的两两相加请为三元函数实现柯里化请简述 refstruct的作用请简述 refreturn的使用方法请利用 foreach和 ref为一个数组中的每个元素加 1请简述 ref、 out和 in在用作函数参数修饰符时的区别请简述非 sealed类的 IDisposable实现方法delegate和 event本质是什么请简述他们的实现机制没错这是一位来自【广州.NET技术俱乐部】微信群的偏 ProgrammingLanguages 编程语言开发科学的大佬本文我将斗胆回答一下这些题目????。由于这些题目对我来说比较难因此我这次只斗胆回答前 10道题发作上篇另外一半的题目再等我慢慢查阅资料另行回答????。解析1. 请简述 async函数的编译方式async/ await是 C# 5.0推出的异步代码编程模型其本质是编译为状态机。只要函数前带上 async就会将函数转换为状态机。2. 请简述 Task状态机的实现和工作机制CPS全称是 ContinuationPassingStyle在 .NET中它会自动编译为将所有引用的局部变量做成闭包放到一个隐藏的 状态机的类中将所有的 await展开成一个状态号有几个 await就有几个状态号每次执行完一个状态都重复回调 状态机的 MoveNext方法同时指定下一个状态号MoveNext方法还需处理线程和异常等问题。3. 请简述 await的作用和原理并说明和 GetResult()有什么区别从状态机的角度出发 await的本质是调用 Task.GetAwaiter()的 UnsafeOnCompleted(Action)回调并指定下一个状态号。从多线程的角度出发如果 await的 Task需要在新的线程上执行该状态机的 MoveNext()方法会立即返回此时主线程被释放出来了然后在 UnsafeOnCompleted回调的 action指定的线程上下文中继续 MoveNext()和下一个状态的代码。而相比之下 GetResult()就是在当前线程上立即等待 Task的完成在 Task完成前当前线程不会释放。注意 Task也可能不一定在新的线程上执行此时用 GetResult()或者 await就只有会不会创建状态机的区别了。4. Task和 Thread有区别吗如果有请简述区别Task和 Thread都能创建用多线程的方式执行代码但它们有较大的区别。Task较新发布于 .NET4.5能结合新的 async/await代码模型写代码它不止能创建新线程还能使用线程池默认、单线程等方式编程在 UI编程领域 Task还能自动返回 UI线程上下文还提供了许多便利 API以管理多个 Task用表格总结如下区别TaskThread.NET版本4.51.1async/await支持不支持创建新线程支持支持线程池/单线程支持不支持返回主线程支持不支持管理API支持不支持TL;DR就是用 Task就对了。5. 简述 yield的作用yield需配合 IEnumerableT一起使用能在一个函数中支持多次不是多个返回其本质和 async/await一样也是状态机。如果不使用 yield需实现 IEnumerableT它只暴露了 GetEnumeratorT这样确保 yield是可重入的比较符合人的习惯。注意其它的语言如 C/ Java/ ES6实现的 yield都叫 generator生成器这相当于 .NET中的 IEnumeratorT而不是 IEnumerableT。这种设计导致 yield不可重入只要其迭代过一次就无法重新迭代了需要注意。6. 利用 IEnumerableT实现斐波那契数列生成IEnumerableint GenerateFibonacci(int n)
{if (n 1) yield return 1;int a 1, b 0;for (int i 2; i n; i){int t b;b a;a t;yield return a;}
}
7. 简述 stackless coroutine和 stackful coroutine的区别并指出 C#的 coroutine是哪一种stackless和 stackful对应的是协程中栈的内存 stackless表示栈内存位置不固定而 stackful则需要分配一个固定的栈内存。在 继续执行 Continuation/ MoveNext()时 stackless需要编译器生成代码如闭包来自定义 继续执行逻辑而 stackful则直接从原栈的位置 继续执行。性能方面 stackful的中断返回需要依赖控制 CPU的跳转位置来实现属于骚操作会略微影响 CPU的分支预测从而影响性能但影响不算大这方面 stackless无影响。内存方面 stackful需要分配一个固定大小的栈内存如 4kb而 stackless只需创建带一个状态号变量的状态机 stackful占用的内存更大。骚操作方面 stackful可以轻松实现完全一致的递归/异常处理等没有任何影响但 stackless需要编译器作者高超的技艺才能实现如 C#的作者注意最初的 C# 5.0在 try-catch块中是不能写 await的。和已有组件结合/框架依赖方面 stackless需要定义一个状态机类型如 TaskT/ IEnumerableT/ IAsyncEnumerableT等而 stackful不需要因此这方面 stackless较麻烦。Go属于 stackful因此每个 goroutine需要分配一个固定大小的内存。C#属于 stackless它会创建一个闭包和状态机需要编译器生成代码来指定 继续执行逻辑。总结如下功能stacklessstackful内存位置不固定固定继续执行编译器定义CPU跳转性能/速度快快但影响分支预测内存占用低需要固定大小的栈内存编译器难度难适中组件依赖不方便方便嵌套不支持支持举例C#/ jsGo/ CBoost8. 请简述 SelectMany的作用相当于 js中数组的 flatMap意思是将序列中的每一条数据转换为0到多条数据。SelectMany可以实现过滤/ .Where方法如下public static IEnumerableT MyWhereT(this IEnumerableT seq, FuncT, bool predicate)
{return seq.SelectMany(x predicate(x) ? new[] { x } : Enumerable.EmptyT());
}
SelectMany是 LINQ中 from关键字的组成部分这一点将在第 10题作演示。9. 请实现一个函数 Compose用于将多个函数复合public static FuncT1, T3 ComposeT1, T2, T3(this FuncT1, T2 f1, FuncT2, T3 f2)
{return x f2(f1(x));
}
然后使用方式Funcint, double log2 x Math.Log2(x);
Funcdouble, string toString x x.ToString();
var log2ToString log2.Compose(toString);
Console.WriteLine(log2ToString(16)); // 4
10. 实现 MaybeT monad并利用 LINQ实现对 Nothing空值和 Just有值的求和本题比较难懂经过和大佬确认本质是要实现如下效果void Main()
{Maybeint a Maybe.Just(5);Maybeint b Maybe.Nothingint();Maybeint c Maybe.Just(10);(from a0 in a from b0 in b select a0 b0).Dump(); // Nothing(from a0 in a from c0 in c select a0 c0).Dump(); // Just 15
}
按照我猴子进化来的大脑的理解应该很自然地能写出如下代码public class MaybeT : IEnumerableT
{public bool HasValue { get; set; }public T Value { get; set;}IEnumerableT ToValue(){if (HasValue) yield return Value;}public IEnumeratorT GetEnumerator(){return ToValue().GetEnumerator();}IEnumerator IEnumerable.GetEnumerator(){return ToValue().GetEnumerator();}
}
public class Maybe
{public static MaybeT JustT(T value){return new MaybeT { Value value, HasValue true};}public static MaybeT NothingT(){return new MaybeT();}
}
这种很自然通过继承 IEnumerableT来实现 LINQ toObjects的基本功能但却是错误答案。正确答案public struct MaybeT
{public readonly bool HasValue;public readonly T Value;public Maybe(bool hasValue, T value){HasValue hasValue;Value value;}public MaybeB SelectManyTCollection, B(FuncT, MaybeTCollection collectionSelector, FuncT, TCollection, B f){if (!HasValue) return Maybe.NothingB();MaybeTCollection collection collectionSelector(Value);if (!collection.HasValue) return Maybe.NothingB();return Maybe.Just(f(Value, collection.Value));}public override string ToString() HasValue ? $Just {Value} : Nothing;
}
public class Maybe
{public static MaybeT JustT(T value){return new MaybeT(true, value);}public static MaybeT NothingT(){return new MaybeT();}
}
注意首先这是一个函数式编程的应用场景它应该使用 struct——值类型。其次不是所有的 LINQ都要走 IEnumerableT可以用手撸的 LINQ表达式—— SelectMany来表示。关于这一点其实特别重要我稍后有空会深入聊聊这一点。总结这些技术平时可能比较冷门全部能回答正确也并不意味着会有多有用可能很难有机会用上。但如果是在开发像 ASP.NETCore那样的超高性能网络服务器、中间件或者 Unity3D那样的高性能游戏引擎、或者做一些高性能实时 ETL之类的就能依靠这些知识做出比肩甚至超过 C/ C的性能同时还能享受 C#/ .NET便利性的产品。群里有人戏称面试时出这些题的公司要么是心太大要么至少得开 60k因此本文取名为 60k大佬。敬请期待我的下篇????。