提交 0e67cb44 编写于 作者: F feilong

增加C#5。0

上级 e1dcb664
{
"type": "code_options",
"author": "huanhuilong",
"source": "Covariance.md",
"notebook_enable": false,
"exercise_id": "5e0d3fafff5f414681d29c840d3d24f5"
}
\ No newline at end of file
# 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
{
"node_id": "csharp-d4650354f5f5498e9969fd98bbb40323",
"keywords": [
"协变和逆变",
"dynamic",
"命名参数",
"可选参数",
"动态查找"
"协变和逆变"
],
"children": [],
"export": [
"Dynamic.json",
"OptionParam.json",
"NamedParam.json",
"Covariance.json",
......
// 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<Article> search = new CodeArticleSearch<CodeArticle>();
// 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<string> Find(string key, int number, bool sort){
Console.WriteLine("key:{0}, number:{1}, sort:{2}", key, number, sort);
return new List<string>(){};
}
}
// 父类和子类
class Article{
public string ToString(){
return "article";
}
}
class CodeArticle: Article{
public string ToString(){
return "article with code";
}
}
// 协变
public interface ISearch<out T> {
T Search();
}
public class CodeArticleSearch<T>: ISearch<T> where T:new(){
public T Search(){
return new T();
}
}
// 逆变
public interface ISend<in T> {
void Send(T t);
}
public class ArticleSender<T> : ISend<T>{
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<string> Find(string key, int number, bool sort){
// Console.WriteLine("key:{0}, number:{1}, sort:{2}", key, number, sort);
// return new List<string>(){};
// }
// }
// // 父类和子类
// class Article{
// public string ToString(){
// return "article";
// }
// }
// class CodeArticle: Article{
// public string ToString(){
// return "article with code";
// }
// }
// // 协变
// public interface ISearch<out T> {
// T Search();
// }
// public class CodeArticleSearch<T>: ISearch<T> where T:new(){
// public T Search(){
// return new T();
// }
// }
// // 逆变
// public interface ISend<in T> {
// void Send(T t);
// }
// public class ArticleSender<T> : ISend<T>{
// public void Send(T t){
// Console.WriteLine("Send:{0}", t.ToString());
// }
// }
\ No newline at end of file
{
"type": "code_options",
"author": "huanhuilong",
"source": "AsyncAwait.md",
"notebook_enable": false,
"exercise_id": "857ced4d29204906b695e8b97ff914ee"
}
\ No newline at end of file
# 异步任务(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
{
"type": "code_options",
"author": "huanhuilong",
"source": "CallerInfo.md",
"notebook_enable": false,
"exercise_id": "1248fc45c96849e383437b49ac38d405"
}
\ No newline at end of file
# 函数调用者信息
通常我们会封装一个函数用来打印日志,但是在在日志函数里,会丢失掉这个日志函数在哪个地方被调用的信息,缺失这个信息会导致诊断问题的时候不方便直接找到出问题的位置。
下面的代码,会在编译期把函数调用位置的信息记录下来,在运行时打印出来。
```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: <Main>$
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
{
"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
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("等我一秒钟");
// }
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>
......@@ -210,10 +210,10 @@
"C#4.0特性": {
"node_id": "csharp-d4650354f5f5498e9969fd98bbb40323",
"keywords": [
"协变和逆变",
"dynamic",
"命名参数",
"可选参数",
"动态查找"
"协变和逆变"
],
"children": [],
"keywords_must": [],
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册