diff --git "a/data/1..NET\345\210\235\351\230\266/3.C#\347\211\271\346\200\247/2.C#4.0\347\211\271\346\200\247/Dynamic.json" "b/data/1..NET\345\210\235\351\230\266/3.C#\347\211\271\346\200\247/2.C#4.0\347\211\271\346\200\247/Dynamic.json" new file mode 100644 index 0000000000000000000000000000000000000000..2b4108f1a0f602a261d975aae5c245ed7f93b6dd --- /dev/null +++ "b/data/1..NET\345\210\235\351\230\266/3.C#\347\211\271\346\200\247/2.C#4.0\347\211\271\346\200\247/Dynamic.json" @@ -0,0 +1,7 @@ +{ + "type": "code_options", + "author": "huanhuilong", + "source": "Covariance.md", + "notebook_enable": false, + "exercise_id": "5e0d3fafff5f414681d29c840d3d24f5" +} \ No newline at end of file diff --git "a/data/1..NET\345\210\235\351\230\266/3.C#\347\211\271\346\200\247/2.C#4.0\347\211\271\346\200\247/Dynamic.md" "b/data/1..NET\345\210\235\351\230\266/3.C#\347\211\271\346\200\247/2.C#4.0\347\211\271\346\200\247/Dynamic.md" new file mode 100644 index 0000000000000000000000000000000000000000..ed7f2c52a4f1fc665d6f613173d2b6fb3eeeeabd --- /dev/null +++ "b/data/1..NET\345\210\235\351\230\266/3.C#\347\211\271\346\200\247/2.C#4.0\347\211\271\346\200\247/Dynamic.md" @@ -0,0 +1,61 @@ +# dynamic 类型 + +下面的代码在编译时时错误的: + +```csharp +// 编译错误,object和int不能相加 +object n = 10; +int result = n + 5; +Console.WriteLine("result:{0}", result); +``` + +而下面的代码可以在编译时通过,运行时正常执行: + +```csharp +// 编译时不检查类型,运行时才检查 +dynamic n = 10; +int result = n + 5; +Console.WriteLine("result:{0}", result); +``` + +dynamic 的用途就是在编译时忽略类型检查,延迟到运行期再检查。现在有下面的代码 + +```csharp +class Test{ + public static dynamic Double(dynamic d){ + if (d is int){ + return d*2; + }else if(d is string){ + return d+d; + }else{ + throw new Exception("Not support"); + } + } +} +``` + +以下关于 上述 dynamic 的代码调用,运行时会出错的是? + +## 答案 + +```csharp +Console.WriteLine(Test.Double(new object())); +``` + +## 选项 + + +### A +```csharp +Console.WriteLine(Test.Double(10)); +``` + +### B +```csharp +Console.WriteLine(Test.Double("10")); +``` + +### C +```csharp +Console.WriteLine(Test.Double(10/2)); +``` \ No newline at end of file diff --git "a/data/1..NET\345\210\235\351\230\266/3.C#\347\211\271\346\200\247/2.C#4.0\347\211\271\346\200\247/config.json" "b/data/1..NET\345\210\235\351\230\266/3.C#\347\211\271\346\200\247/2.C#4.0\347\211\271\346\200\247/config.json" index 3d1b86f883e634bdce80579d1b3026459568da27..aacea1c624184bf0c0670d3a152e883604e97642 100644 --- "a/data/1..NET\345\210\235\351\230\266/3.C#\347\211\271\346\200\247/2.C#4.0\347\211\271\346\200\247/config.json" +++ "b/data/1..NET\345\210\235\351\230\266/3.C#\347\211\271\346\200\247/2.C#4.0\347\211\271\346\200\247/config.json" @@ -1,13 +1,14 @@ { "node_id": "csharp-d4650354f5f5498e9969fd98bbb40323", "keywords": [ - "协变和逆变", + "dynamic", "命名参数", "可选参数", - "动态查找" + "协变和逆变" ], "children": [], "export": [ + "Dynamic.json", "OptionParam.json", "NamedParam.json", "Covariance.json", diff --git "a/data/1..NET\345\210\235\351\230\266/3.C#\347\211\271\346\200\247/2.C#4.0\347\211\271\346\200\247/sample/Program.cs" "b/data/1..NET\345\210\235\351\230\266/3.C#\347\211\271\346\200\247/2.C#4.0\347\211\271\346\200\247/sample/Program.cs" index 531534effa1dd8ba50a493b6b163d5359bd810c0..f7d1cabb1ac24ed40898ab06ba8c06d6b2646e5a 100644 --- "a/data/1..NET\345\210\235\351\230\266/3.C#\347\211\271\346\200\247/2.C#4.0\347\211\271\346\200\247/sample/Program.cs" +++ "b/data/1..NET\345\210\235\351\230\266/3.C#\347\211\271\346\200\247/2.C#4.0\347\211\271\346\200\247/sample/Program.cs" @@ -1,6 +1,36 @@ // See https://aka.ms/new-console-template for more information Console.WriteLine("Hello, World!"); + + +Console.WriteLine(Test.Double(10/2)); +// Console.WriteLine(Test.Double("10")); +// Console.WriteLine(Test.Double(new object())); + +class Test{ + public static dynamic Double(dynamic d){ + if (d is int){ + return d*2; + }else if(d is string){ + return d+d; + }else{ + throw new Exception("Not support"); + } + } +} + + + +// 编译错误 +// object n = 10; +// int result = n + 5; +// Console.WriteLine("result:{0}", result); + +// 编译时不检查,运行时才检查 +// dynamic n = "10"; +// int result = n + 5; +// Console.WriteLine("result:{0}", result); + // // // 协变代码 // ISearch
search = new CodeArticleSearch(); // Article article = search.Search(); @@ -18,50 +48,50 @@ Console.WriteLine("Hello, World!"); // Test.Find(key:"hello", number:5); -Test.Find(key:"hello", sort:false, number:5); -Test.Find(sort:false, number:5, key:"hello"); - - -static class Test{ - public static List Find(string key, int number, bool sort){ - Console.WriteLine("key:{0}, number:{1}, sort:{2}", key, number, sort); - return new List(){}; - } -} - - -// 父类和子类 -class Article{ - public string ToString(){ - return "article"; - } -} - -class CodeArticle: Article{ - public string ToString(){ - return "article with code"; - } -} - - -// 协变 -public interface ISearch { - T Search(); -} - -public class CodeArticleSearch: ISearch where T:new(){ - public T Search(){ - return new T(); - } -} - -// 逆变 -public interface ISend { - void Send(T t); -} - -public class ArticleSender : ISend{ - public void Send(T t){ - Console.WriteLine("Send:{0}", t.ToString()); - } -} \ No newline at end of file +// Test.Find(key:"hello", sort:false, number:5); +// Test.Find(sort:false, number:5, key:"hello"); + + +// static class Test{ +// public static List Find(string key, int number, bool sort){ +// Console.WriteLine("key:{0}, number:{1}, sort:{2}", key, number, sort); +// return new List(){}; +// } +// } + + +// // 父类和子类 +// class Article{ +// public string ToString(){ +// return "article"; +// } +// } + +// class CodeArticle: Article{ +// public string ToString(){ +// return "article with code"; +// } +// } + + +// // 协变 +// public interface ISearch { +// T Search(); +// } + +// public class CodeArticleSearch: ISearch where T:new(){ +// public T Search(){ +// return new T(); +// } +// } + +// // 逆变 +// public interface ISend { +// void Send(T t); +// } + +// public class ArticleSender : ISend{ +// public void Send(T t){ +// Console.WriteLine("Send:{0}", t.ToString()); +// } +// } \ No newline at end of file diff --git "a/data/1..NET\345\210\235\351\230\266/3.C#\347\211\271\346\200\247/3.C#5.0\347\211\271\346\200\247/AsyncAwait.json" "b/data/1..NET\345\210\235\351\230\266/3.C#\347\211\271\346\200\247/3.C#5.0\347\211\271\346\200\247/AsyncAwait.json" new file mode 100644 index 0000000000000000000000000000000000000000..471385e71309f4bd75600d6a44d88261d945a1b2 --- /dev/null +++ "b/data/1..NET\345\210\235\351\230\266/3.C#\347\211\271\346\200\247/3.C#5.0\347\211\271\346\200\247/AsyncAwait.json" @@ -0,0 +1,7 @@ +{ + "type": "code_options", + "author": "huanhuilong", + "source": "AsyncAwait.md", + "notebook_enable": false, + "exercise_id": "857ced4d29204906b695e8b97ff914ee" +} \ No newline at end of file diff --git "a/data/1..NET\345\210\235\351\230\266/3.C#\347\211\271\346\200\247/3.C#5.0\347\211\271\346\200\247/AsyncAwait.md" "b/data/1..NET\345\210\235\351\230\266/3.C#\347\211\271\346\200\247/3.C#5.0\347\211\271\346\200\247/AsyncAwait.md" new file mode 100644 index 0000000000000000000000000000000000000000..4b6eec73340ceb733999e34efd9958c533566bfd --- /dev/null +++ "b/data/1..NET\345\210\235\351\230\266/3.C#\347\211\271\346\200\247/3.C#5.0\347\211\271\346\200\247/AsyncAwait.md" @@ -0,0 +1,137 @@ +# 异步任务(async, await, Task) + +下面的代码是同步执行的: +```csharp +// 同步 +Console.WriteLine("调用 DoSomethingSync 之前"); +DoSomethingSync(); +Console.WriteLine("调用 DoSomethingSync 之后"); + +void DoSomethingSync(){ + Thread.Sleep(1000); + Console.WriteLine("等我一秒钟"); +} +``` + +输出的结果是: + +```csharp +调用 DoSomethingSync 之前 +等我一秒钟 +调用 DoSomethingSync 之后 +``` + +而下面的代码是异步执行的: + +```csharp +// 异步 +Console.WriteLine("调用 DoSomethingAsync 之前"); +Task task = DoSomethingAsync(); +Console.WriteLine("调用 DoSomethingAsync 之后"); + +await task; + +async Task DoSomethingAsync(){ + await Task.Delay(10000); + Console.WriteLine("等我一秒钟"); +} +``` + +输出结果是: + +```csharp +调用 DoSomethingAsync 之前 +调用 DoSomethingAsync 之后 +等我一秒钟 +``` + +几个关键的地方是 +* async 方法必须返回一个Task +* 一个 Task 可以被异步执行,程序继续往下执行主线逻辑 +* 一个 Task,可以被 await(异步等待) +* 通过 await 一个Task,则必须等待异步任务完成后才继续往下执行 + +下面关于 async, await 说法错误的是? + +## 答案 + +```csharp +// 以下代码的输出是 +// == +// "调用 DoSomethingAsync 之前" +// "调用 DoSomethingAsync 之后" +// "等我一秒钟" +// +Console.WriteLine("调用 DoSomethingAsync 之前"); +Task task = DoSomethingAsync(); +Console.WriteLine("调用 DoSomethingAsync 之后"); + +await task; + +async Task DoSomethingAsync(){ + await Thread.Sleep(1000); + Console.WriteLine("等我一秒钟"); +} +``` + +## 选项 + +### A + +```csharp +// 以下代码的输出是 +// == +// "调用 DoSomethingAsync 之前" +// "等我一秒钟" +// "调用 DoSomethingAsync 之后" +// +Console.WriteLine("调用 DoSomethingAsync 之前"); +Task task = DoSomethingAsync(); +Console.WriteLine("调用 DoSomethingAsync 之后"); + +await task; + +async Task DoSomethingAsync(){ + Task.Delay(10000); + Console.WriteLine("等我一秒钟"); +} +``` + +### B + +```csharp +// 以下代码的输出是 +// == +// "调用 DoSomethingAsync 之前" +// "调用 DoSomethingAsync 之后" +// +Console.WriteLine("调用 DoSomethingAsync 之前"); +Task task = DoSomethingAsync(); +Console.WriteLine("调用 DoSomethingAsync 之后"); + +async Task DoSomethingAsync(){ + Thread.Sleep(1000); + Console.WriteLine("等我一秒钟"); +} +``` + +### C + +```csharp +// 以下代码的输出是 +// == +// "调用 DoSomethingAsync 之前" +// "调用 DoSomethingAsync 之后" +// "等我一秒钟" +// +Console.WriteLine("调用 DoSomethingAsync 之前"); +Task task = DoSomethingAsync(); +Console.WriteLine("调用 DoSomethingAsync 之后"); +await task; + +async Task DoSomethingAsync(){ + Task delay = Task.Delay(1000); + await delay; + Console.WriteLine("等我一秒钟"); +} +``` \ No newline at end of file diff --git "a/data/1..NET\345\210\235\351\230\266/3.C#\347\211\271\346\200\247/3.C#5.0\347\211\271\346\200\247/CallerInfo.json" "b/data/1..NET\345\210\235\351\230\266/3.C#\347\211\271\346\200\247/3.C#5.0\347\211\271\346\200\247/CallerInfo.json" new file mode 100644 index 0000000000000000000000000000000000000000..fb6aa8156cb95159601252d491b2958c6052df12 --- /dev/null +++ "b/data/1..NET\345\210\235\351\230\266/3.C#\347\211\271\346\200\247/3.C#5.0\347\211\271\346\200\247/CallerInfo.json" @@ -0,0 +1,7 @@ +{ + "type": "code_options", + "author": "huanhuilong", + "source": "CallerInfo.md", + "notebook_enable": false, + "exercise_id": "1248fc45c96849e383437b49ac38d405" +} \ No newline at end of file diff --git "a/data/1..NET\345\210\235\351\230\266/3.C#\347\211\271\346\200\247/3.C#5.0\347\211\271\346\200\247/CallerInfo.md" "b/data/1..NET\345\210\235\351\230\266/3.C#\347\211\271\346\200\247/3.C#5.0\347\211\271\346\200\247/CallerInfo.md" new file mode 100644 index 0000000000000000000000000000000000000000..ff1a9d6c1e81e303263bc6bda4666c2a8e7f80d6 --- /dev/null +++ "b/data/1..NET\345\210\235\351\230\266/3.C#\347\211\271\346\200\247/3.C#5.0\347\211\271\346\200\247/CallerInfo.md" @@ -0,0 +1,103 @@ +# 函数调用者信息 + +通常我们会封装一个函数用来打印日志,但是在在日志函数里,会丢失掉这个日志函数在哪个地方被调用的信息,缺失这个信息会导致诊断问题的时候不方便直接找到出问题的位置。 + +下面的代码,会在编译期把函数调用位置的信息记录下来,在运行时打印出来。 + +```csharp +using System.Runtime.CompilerServices; + +TraceMessage("HelloWorld"); + +void TraceMessage(string message, + [CallerMemberName] string memberName = "", + [CallerFilePath] string sourceFilePath = "", + [CallerLineNumber] int sourceLineNumber = 0) +{ + Console.WriteLine("message: " + message); + Console.WriteLine("member name: " + memberName); + Console.WriteLine("source file path: " + sourceFilePath); + Console.WriteLine("source line number: " + sourceLineNumber); +} +``` + +输出信息是: +```bash +message: HelloWorld +member name:
$ +source file path: ...../Program.cs +source line number: 3 +``` + +以下说法错误的是? + +## 答案 + +```csharp +使用调用者信息属性,不需要引入 using System.Runtime.CompilerServices; +``` + + +## 选项 + +### A + +```csharp +[CallerMemberName] 是函数参数的属性标记,这是CSharp特有的语法 +``` + +### B + +```csharp +// +// (1)和(2)输出的 source line number 不同 +// + +using System.Runtime.CompilerServices; + +Test(); + +void Test(){ + TraceMessage("HelloWorld"); //(1) + TraceMessage("HelloWorld"); //(2) +} + +void TraceMessage(string message, + [CallerMemberName] string memberName = "", + [CallerFilePath] string sourceFilePath = "", + [CallerLineNumber] int sourceLineNumber = 0) +{ + Console.WriteLine("message: " + message); + Console.WriteLine("member name: " + memberName); + Console.WriteLine("source file path: " + sourceFilePath); + Console.WriteLine("source line number: " + sourceLineNumber); +} +``` + +### C + +```csharp +// +// (1)和(2)输出的 source file path 和 member name 相同 +// + +using System.Runtime.CompilerServices; + +Test(); + +void Test(){ + TraceMessage("HelloWorld"); //(1) + TraceMessage("HelloWorld"); //(2) +} + +void TraceMessage(string message, + [CallerMemberName] string memberName = "", + [CallerFilePath] string sourceFilePath = "", + [CallerLineNumber] int sourceLineNumber = 0) +{ + Console.WriteLine("message: " + message); + Console.WriteLine("member name: " + memberName); + Console.WriteLine("source file path: " + sourceFilePath); + Console.WriteLine("source line number: " + sourceLineNumber); +} +``` \ No newline at end of file diff --git "a/data/1..NET\345\210\235\351\230\266/3.C#\347\211\271\346\200\247/3.C#5.0\347\211\271\346\200\247/config.json" "b/data/1..NET\345\210\235\351\230\266/3.C#\347\211\271\346\200\247/3.C#5.0\347\211\271\346\200\247/config.json" index 4acd3e86da0c3fb21eb1dead3b00c2baf5331f10..9d967bd9afbc7870c9a835f53ed300f61fc5971c 100644 --- "a/data/1..NET\345\210\235\351\230\266/3.C#\347\211\271\346\200\247/3.C#5.0\347\211\271\346\200\247/config.json" +++ "b/data/1..NET\345\210\235\351\230\266/3.C#\347\211\271\346\200\247/3.C#5.0\347\211\271\346\200\247/config.json" @@ -1,14 +1,15 @@ { "node_id": "csharp-730d385761c64702b710308c91271c9c", "keywords": [ - "case支持表达式", - "带参数的泛型构造函数", - "扩展属性", - "支持null类型运算", - "绑定运算符,:=:" + "async", + "await", + "caller information" ], "children": [], - "export": [], + "export": [ + "AsyncAwait.json", + "CallerInfo.json" + ], "keywords_must": [], "keywords_forbid": [] } \ No newline at end of file diff --git "a/data/1..NET\345\210\235\351\230\266/3.C#\347\211\271\346\200\247/3.C#5.0\347\211\271\346\200\247/sample/Program.cs" "b/data/1..NET\345\210\235\351\230\266/3.C#\347\211\271\346\200\247/3.C#5.0\347\211\271\346\200\247/sample/Program.cs" new file mode 100644 index 0000000000000000000000000000000000000000..7582f5592589fa5d4966da22ffbdec049947366d --- /dev/null +++ "b/data/1..NET\345\210\235\351\230\266/3.C#\347\211\271\346\200\247/3.C#5.0\347\211\271\346\200\247/sample/Program.cs" @@ -0,0 +1,51 @@ +using System.Runtime.CompilerServices; + +Test(); + +void Test(){ + TraceMessage("HelloWorld"); //(1) + TraceMessage("HelloWorld"); //(2) +} + +void TraceMessage(string message, + [CallerMemberName] string memberName = "", + [CallerFilePath] string sourceFilePath = "", + [CallerLineNumber] int sourceLineNumber = 0) +{ + Console.WriteLine("message: " + message); + Console.WriteLine("member name: " + memberName); + Console.WriteLine("source file path: " + sourceFilePath); + Console.WriteLine("source line number: " + sourceLineNumber); +} + +// 同步 +// Console.WriteLine("调用 DoSomethingSync 之前"); +// DoSomethingSync(); +// Console.WriteLine("调用 DoSomethingSync 之后"); + +// void DoSomethingSync(){ +// Thread.Sleep(1000); +// Console.WriteLine("等我一秒钟"); +// } + +// 异步 + +// Console.WriteLine("调用 DoSomethingAsync 之前"); +// Task task = DoSomethingAsync(); +// Console.WriteLine("调用 DoSomethingAsync 之后"); +// await task; + +// async Task DoSomethingAsync(){ +// Task delay = Task.Delay(1000); +// await delay; +// Console.WriteLine("等我一秒钟"); +// } + + + + + + + + + diff --git "a/data/1..NET\345\210\235\351\230\266/3.C#\347\211\271\346\200\247/3.C#5.0\347\211\271\346\200\247/sample/sample.csproj" "b/data/1..NET\345\210\235\351\230\266/3.C#\347\211\271\346\200\247/3.C#5.0\347\211\271\346\200\247/sample/sample.csproj" new file mode 100644 index 0000000000000000000000000000000000000000..40c60dd4c884340c455eab8a0020f7c681a4e76c --- /dev/null +++ "b/data/1..NET\345\210\235\351\230\266/3.C#\347\211\271\346\200\247/3.C#5.0\347\211\271\346\200\247/sample/sample.csproj" @@ -0,0 +1,10 @@ + + + + Exe + net6.0 + enable + enable + + + diff --git a/data/tree.json b/data/tree.json index 48ba95eb90f6fc92f310dbb1dae9254ecb97b36f..ce1276b92169ac6acc56f22f22c24f4feaaa9d42 100644 --- a/data/tree.json +++ b/data/tree.json @@ -210,10 +210,10 @@ "C#4.0特性": { "node_id": "csharp-d4650354f5f5498e9969fd98bbb40323", "keywords": [ - "协变和逆变", + "dynamic", "命名参数", "可选参数", - "动态查找" + "协变和逆变" ], "children": [], "keywords_must": [],