"[번역] C# 7의 새로운 기능"은 C# 7.0의 9가지 새로운 기능을 소개하는 데 많은 시간을 할애합니다. 여기서는 누구나 쉽게 배울 수 있도록 프로젝트 경험을 바탕으로 예제를 통해 빠르게 소개하겠습니다. 짧은 시간 안에 그들에 대해 알아보세요.
일반적으로 이러한 새로운 기능을 사용하면 C# 7.0의 함수형 프로그래밍 아이디어로 코드를 더 쉽게 작성할 수 있습니다. C# 6.0은 이 과정에서 많은 작업을 수행했으며 C# 7.0은 한 단계 더 가까워졌습니다!
C# 6.0에서는 멤버 메서드와 읽기 전용 속성에 대해 Lambda 표현식을 사용할 수 있습니다. 당시 가장 답답했던 점은 속성의 set 접근자가 지원되지 않는 이유였습니다. . 이제 set 메소드는 람다 표현식 사용을 지원할 뿐만 아니라 생성자, 소멸자 및 인덱스도 람다 표현식에서 정의할 수 있습니다.
class SomeModel { private string internalValue; public string Value { get => internalValue; set => internalValue = string.IsNullOrWhiteSpace(value) ? null : value; } }
out
변수 out
변수는 이전에 존재했던 구문입니다. C# 7.0에서는 코드 한 줄을 더 쓰지 않기 위해 선언과 사용을 함께 사용할 수 있습니다. 가장 직접적인 효과는 하나의 표현식으로 두 개의 명령문을 완성할 수 있다는 것입니다. 다음은 Key
클래스의 단순화된 버전입니다. 이 클래스는 HTTP Get/Post를 통해 전달된 ID 값을 처리하기 위해 초기에 사용되었습니다.
public class Key { public string Value { get; } public Key(string key) { Value = key; } public int IntValue { get { // C# 6.0,需要提前定义 intValue,但不需要初始化 // 虽然 C# 6.0 可以为只读属性使用 Lambda 表达式 // 但这里无法用一个表达式表达出来 int intValue; return int.TryParse(Value, out intValue) ? intValue : 0; } } }
근데 C# 7에서는 간단해요
// 注意 out var intValue, // 对于可推导的类型甚至可以用 var 来申明变量 public int IntValue => int.TryParse(Value, out var intValue) ? intValue : 0;
System.Tuple
를 써본 친구들은 Item1
과 Item2
를 이렇게 생각해야 해요 무의미한 이름에 매우 불쾌감을 느낍니다. 그러나 C# 7.0에서는 의미 체계 명명 기능을 제공하는 동시에 튜플 생성을 줄여 Tuple.Create(...)
가 필요하지 않습니다. 또한 새로운 튜플 기능과 구조 분해를 사용하려면 NuGet 패키지System.ValueTuple
를 도입해야 합니다.
Install-Package System.ValueTuple
물론 튜플은 여러 값을 반환하는 메서드에 자주 사용됩니다. 어떤 사람들은 반환에 out
매개변수를 사용하는 것을 좋아하지만, 이제 out
변수가 가능하더라도 나는 여전히 out
매개변수가 널리 사용되는 것을 선호하지 않습니다.
다음 예시 메소드는 데이터 검색을 위한 기본 시간 범위(오늘부터 시작하여 총 7일)를 반환하는 데 사용됩니다.
// 返回类型是一个包含两个元素的元组 (DateTime Begin, DateTime End) GetDefaultDateRange() { var end = DateTime.Today.AddDays(1); var begin = end.AddDays(-7); // 这里使用一对圆括号就创建了一个元组 return (begin, end); }
튜플을 가져오려면 이 메소드를 호출하세요. 반환 값은 정의될 때 각 데이터 멤버의 이름을 지정하기 때문에 튜플에서 데이터를 가져오는 것이 의미론적일 수 있습니다. 그리고 Item1
. Item2
var range = GetDefaultDateRange(); var begin = range.Begin; // 也可以 begin = range.Item1 var end = range.End; // 也可以 end = range.Item2위의 예는 중간 변수
를 사용하지 않고 단순화할 수 있습니다. 이는 구조 분해를 사용합니다. range
var (begin, end) = GetDefaultDateRange();여기서 생성된 튜플은 실제로 반환 값으로 예시됩니다. 어디에서나 튜플을 만들 수 있습니다. 위 예제의 논리는 매우 간단하며 표현식을 사용하여 해결할 수 있습니다. 다음 예제에서는 의미 없는 반환 유형 선언을 보여줍니다.
// 原来的 (DateTime Begin, DateTime End) 申明也是没问题的 (DateTime, DateTime) GetDefaultDateRange() => (DateTime.Today.AddDays(1).AddDays(-7), DateTime.Today.AddDays(1));구조 분해 방법 Deconstrct구조 분해 방법을 사용하면 정의된 매개 변수에 따라 모든 클래스(튜플뿐만 아니라)를 구조 분해할 수 있습니다. 그리고 놀라운 점은 구조해제 메서드가 멤버 메서드일 수도 있고 확장 메서드로 정의될 수도 있다는 것입니다.
public class Size { public int Width { get; } public int Height { get; } public int Tall { get; } public Size(int width, int height, int tall) { this.Width = width; this.Height = height; this.Tall = tall; } // 定义成成员方法的解构 public void Deconstruct(out int width, out int height) { width = Width; height = Height; } } public static class SizeExt { // 定义成扩展方法的解构 public static void Deconstruct(this Size size, out int width, out int height, out int tall) { width = size.Width; height = size.Height; tall = size.Tall; } }다음은 구조 분해
var size = new Size(1920, 1080, 10); var (w, h) = size; var (x, y, z) = size;를 사용하여
Size
public Size(int width, int height, int tall) => (Width, Height, Tall) = (width, height, tall);패턴 매칭현재 패턴 매칭은
과 is
을 지원합니다. 아주 거창한 이름처럼 들리지만, 좀 더 현실적으로 말하면 유형을 판단하고 특정 유형의 참조를 정의하는 것을 의미하며 관심이 있는 경우 몇 가지 추가 판단을 추가할 수 있습니다. switch
의 경우 판단할 때 변수를 정의하고 초기화하는 것이므로 is
// 假设逻辑能保证这里的 v 可能是 string 也 可能是 int string ToString(object v) { if (v is int) { int n = (int) v; return n.ToString("X4"); } else { return (string) n; } }와 같이 작성한 코드는 - 뭐, 한 단계만 단순화하면 됩니다. 표현식으로 작성
string ToString(object v) => (v is int n) ? n.ToString("X4") : (string) v;
물론 이전 표현식도 표현식으로 단순화할 수 있다고 말할 수 있습니다. 알았어, 이 문제는 깊이 파고들지 말자, 알았지? 저는 단지에 대한 패턴 일치를 시연하고 있을 뿐입니다.
is
의 패턴 일치가 훨씬 더 유용한 것 같습니다. ToString을 예로 들어보겠습니다. switch
static string ToString(object v) { switch (v) { case int n when n > 0xffff: // 判断类型,匹配的情况下再对值进行一个判断 return n.ToString("X8"); case int n: // 判断类型,这里 n 肯定 <= 0xffff return n.ToString("X4"); case bool b: return b ? "ON" : "OFF"; case null: return null; default: return v.ToString(); } }위의 첫 번째 브랜치에서
의 사용법에 주의하세요. . 괜찮은. when
, out
의 사용은 거의 피할 수 있다고 개인적으로 생각합니다. ref
접두사가 있는 이진 숫자 리터럴 구문을 도입한 것이고, 다른 하나는 <를 임의로 사용할 수 있다는 것입니다. 🎜> 그룹 번호. 과반수가 필요하지 않습니다. 이해를 돕기 위해 두 가지 예만 제시하면 됩니다. 0b
const int MARK_THREE = 0b11; // 0x03 const int LONG_MARK = 0b_1111_1111; // 0xff const double PI = 3.14_1592_6536
经常写 JavaScript 的同学肯定会深有体会,局部函数是个好东西。当然它在 C# 中带来的最大好处是将某些代码组织在了一起。我之前在项目中大量使用了 Lambda 来代替局部函数,现在可以直接替换成局部函数了。Labmda 和局部函数虽然多数情况下能做同样的事情,但是它们仍然有一些区别
对于 Lambda,编译器要干的事情比较多。总之呢,就是编译效率要低得多
Lambda 通过委托实现,调用过程比较复杂,局部函数可以直接调用。简单地说就是局部函数执行效率更高
Lambda 必须先定义再使用,局部函数可以定义在使用之后。据说这在对递归算法的支持上会有区别
比较常用的地方是 Enumerator 函数和 async 函数中,因为它们实际都不是立即执行的。
我在项目中多是用来组织代码。局部函数代替只被某一个公共 API 调用的私有函数来组织代码虽然不失为一个简化类结构的好方法,但是把公共 API 函数的函数体拉长。所以很多时候我也会使用内部类来代替某些私有函数来组织代码。这里顺便说一句,我不赞成使用 #region
组织代码。
如果和 JavaScript 中 ES2017 的 async 相比,C# 中的 Task/Task<T> 就比较像 <code>Promise
的角色。不用羡慕 JavaScript 的 async 支持 Promise like,现在 C# 的 async 也支持 Task like 了,只要实现了 GetAwaiter
方法就行。
官方提供了一个 ValueTask
作为示例,可以通过 NuGet 引入:
Install-Package System.Threading.Tasks.Extensions
这个 ValueTask
比较有用的一点就是兼容了数据类型和 Task:
string cache; ValueTask<string> GetData() { return cache == null ? new ValueTask<string>(cache) : new ValueTask<string>(GetRemoteData()); // 局部函数 async Task<string> GetRemoteData() { await Task.Delay(100); return "hello async"; } }
"[번역] C# 7의 새로운 기능"은 C# 7.0의 9가지 새로운 기능을 소개하는 데 많은 시간을 할애합니다. 여기서는 누구나 쉽게 배울 수 있도록 프로젝트 경험을 바탕으로 예제를 통해 빠르게 소개하겠습니다. 짧은 시간 안에 그들에 대해 알아보세요.
일반적으로 이러한 새로운 기능을 사용하면 C# 7.0의 함수형 프로그래밍 아이디어로 코드를 더 쉽게 작성할 수 있습니다. C# 6.0은 이 과정에서 많은 작업을 수행했으며 C# 7.0은 한 단계 더 가까워졌습니다!
C# 6.0에서는 멤버 메서드와 읽기 전용 속성에 대해 Lambda 표현식을 사용할 수 있습니다. 당시 가장 답답했던 점은 속성의 set 접근자가 지원되지 않는 이유였습니다. . 이제 set 메소드는 람다 표현식 사용을 지원할 뿐만 아니라 생성자, 소멸자 및 인덱스도 람다 표현식에서 정의할 수 있습니다.
class SomeModel { private string internalValue; public string Value { get => internalValue; set => internalValue = string.IsNullOrWhiteSpace(value) ? null : value; } }
out
변수 out
변수는 이전에 존재했던 구문입니다. C# 7.0에서는 코드 한 줄을 더 쓰지 않기 위해 선언과 사용을 함께 사용할 수 있습니다. 가장 직접적인 효과는 하나의 표현식으로 두 개의 명령문을 완성할 수 있다는 것입니다. 다음은 Key
클래스의 단순화된 버전입니다. 이 클래스는 HTTP Get/Post를 통해 전달된 ID 값을 처리하기 위해 초기에 사용되었습니다.
public class Key { public string Value { get; } public Key(string key) { Value = key; } public int IntValue { get { // C# 6.0,需要提前定义 intValue,但不需要初始化 // 虽然 C# 6.0 可以为只读属性使用 Lambda 表达式 // 但这里无法用一个表达式表达出来 int intValue; return int.TryParse(Value, out intValue) ? intValue : 0; } } }
근데 C# 7에서는 간단해요
// 注意 out var intValue, // 对于可推导的类型甚至可以用 var 来申明变量 public int IntValue => int.TryParse(Value, out var intValue) ? intValue : 0;
System.Tuple
를 써본 친구들은 Item1
과 Item2
를 이렇게 생각해야 해요 무의미한 이름에 매우 불쾌감을 느낍니다. 그러나 C# 7.0에서는 의미 체계 명명 기능을 제공하는 동시에 튜플 생성을 줄여 Tuple.Create(...)
가 필요하지 않습니다. 또한 새로운 튜플 기능과 구조 분해를 사용하려면 NuGet 패키지System.ValueTuple
를 도입해야 합니다.
Install-Package System.ValueTuple
물론 튜플은 여러 값을 반환하는 메서드에 자주 사용됩니다. 어떤 사람들은 반환에 out
매개변수를 사용하는 것을 좋아하지만, 이제 out
변수가 가능하더라도 나는 여전히 out
매개변수가 널리 사용되는 것을 선호하지 않습니다.
다음 예시 메소드는 데이터 검색을 위한 기본 시간 범위(오늘부터 시작하여 총 7일)를 반환하는 데 사용됩니다.
// 返回类型是一个包含两个元素的元组 (DateTime Begin, DateTime End) GetDefaultDateRange() { var end = DateTime.Today.AddDays(1); var begin = end.AddDays(-7); // 这里使用一对圆括号就创建了一个元组 return (begin, end); }
튜플을 가져오려면 이 메소드를 호출하세요. 반환 값은 정의될 때 각 데이터 멤버의 이름을 지정하기 때문에 튜플에서 데이터를 가져오는 것이 의미론적일 수 있습니다. 그리고 Item1
. Item2
var range = GetDefaultDateRange(); var begin = range.Begin; // 也可以 begin = range.Item1 var end = range.End; // 也可以 end = range.Item2위의 예는 중간 변수
를 사용하지 않고 단순화할 수 있습니다. 이는 구조 분해를 사용합니다. range
var (begin, end) = GetDefaultDateRange();여기서 생성된 튜플은 실제로 반환 값으로 예시됩니다. 어디에서나 튜플을 만들 수 있습니다. 위 예제의 논리는 매우 간단하며 표현식을 사용하여 해결할 수 있습니다. 다음 예제에서는 의미 없는 반환 유형 선언을 보여줍니다.
// 原来的 (DateTime Begin, DateTime End) 申明也是没问题的 (DateTime, DateTime) GetDefaultDateRange() => (DateTime.Today.AddDays(1).AddDays(-7), DateTime.Today.AddDays(1));구조 분해 방법 Deconstrct구조 분해 방법을 사용하면 정의된 매개 변수에 따라 모든 클래스(튜플뿐만 아니라)를 구조 분해할 수 있습니다. 그리고 놀라운 점은 구조해제 메서드가 멤버 메서드일 수도 있고 확장 메서드로 정의될 수도 있다는 것입니다.
public class Size { public int Width { get; } public int Height { get; } public int Tall { get; } public Size(int width, int height, int tall) { this.Width = width; this.Height = height; this.Tall = tall; } // 定义成成员方法的解构 public void Deconstruct(out int width, out int height) { width = Width; height = Height; } } public static class SizeExt { // 定义成扩展方法的解构 public static void Deconstruct(this Size size, out int width, out int height, out int tall) { width = size.Width; height = size.Height; tall = size.Tall; } }다음은 구조 분해
var size = new Size(1920, 1080, 10); var (w, h) = size; var (x, y, z) = size;를 사용하여
Size
public Size(int width, int height, int tall) => (Width, Height, Tall) = (width, height, tall);패턴 매칭현재 패턴 매칭은
과 is
을 지원합니다. 아주 거창한 이름처럼 들리지만, 좀 더 현실적으로 말하면 유형을 판단하고 특정 유형의 참조를 정의하는 것을 의미하며 관심이 있는 경우 몇 가지 추가 판단을 추가할 수 있습니다. switch
의 경우 판단할 때 변수를 정의하고 초기화하는 것이므로 is
// 假设逻辑能保证这里的 v 可能是 string 也 可能是 int string ToString(object v) { if (v is int) { int n = (int) v; return n.ToString("X4"); } else { return (string) n; } }와 같이 작성한 코드는 - 뭐, 한 단계만 단순화하면 됩니다. 표현식으로 작성
string ToString(object v) => (v is int n) ? n.ToString("X4") : (string) v;
물론 이전 표현식도 표현식으로 단순화할 수 있다고 말할 수 있습니다. 알았어, 이 문제는 깊이 파고들지 말자, 알았지? 저는 단지에 대한 패턴 일치를 시연하고 있을 뿐입니다.
is
의 패턴 일치가 훨씬 더 유용한 것 같습니다. ToString을 예로 들어보겠습니다. switch
static string ToString(object v) { switch (v) { case int n when n > 0xffff: // 判断类型,匹配的情况下再对值进行一个判断 return n.ToString("X8"); case int n: // 判断类型,这里 n 肯定 <= 0xffff return n.ToString("X4"); case bool b: return b ? "ON" : "OFF"; case null: return null; default: return v.ToString(); } }위의 첫 번째 브랜치에서
의 사용법에 주의하세요. . 괜찮은. when
, out
의 사용은 거의 피할 수 있다고 개인적으로 생각합니다. ref
접두사가 있는 이진 숫자 리터럴 구문을 도입한 것이고, 다른 하나는 <를 임의로 사용할 수 있다는 것입니다. 🎜> 그룹 번호. 과반수가 필요하지 않습니다. 이해를 돕기 위해 두 가지 예만 제시하면 됩니다. 0b
const int MARK_THREE = 0b11; // 0x03 const int LONG_MARK = 0b_1111_1111; // 0xff const double PI = 3.14_1592_6536
经常写 JavaScript 的同学肯定会深有体会,局部函数是个好东西。当然它在 C# 中带来的最大好处是将某些代码组织在了一起。我之前在项目中大量使用了 Lambda 来代替局部函数,现在可以直接替换成局部函数了。Labmda 和局部函数虽然多数情况下能做同样的事情,但是它们仍然有一些区别
对于 Lambda,编译器要干的事情比较多。总之呢,就是编译效率要低得多
Lambda 通过委托实现,调用过程比较复杂,局部函数可以直接调用。简单地说就是局部函数执行效率更高
Lambda 必须先定义再使用,局部函数可以定义在使用之后。据说这在对递归算法的支持上会有区别
比较常用的地方是 Enumerator 函数和 async 函数中,因为它们实际都不是立即执行的。
我在项目中多是用来组织代码。局部函数代替只被某一个公共 API 调用的私有函数来组织代码虽然不失为一个简化类结构的好方法,但是把公共 API 函数的函数体拉长。所以很多时候我也会使用内部类来代替某些私有函数来组织代码。这里顺便说一句,我不赞成使用 #region
组织代码。
如果和 JavaScript 中 ES2017 的 async 相比,C# 中的 Task/Task<T> 就比较像 <code>Promise
的角色。不用羡慕 JavaScript 的 async 支持 Promise like,现在 C# 的 async 也支持 Task like 了,只要实现了 GetAwaiter
方法就行。
官方提供了一个 ValueTask
作为示例,可以通过 NuGet 引入:
Install-Package System.Threading.Tasks.Extensions
这个 ValueTask
比较有用的一点就是兼容了数据类型和 Task:
string cache; ValueTask<string> GetData() { return cache == null ? new ValueTask<string>(cache) : new ValueTask<string>(GetRemoteData()); // 局部函数 async Task<string> GetRemoteData() { await Task.Delay(100); return "hello async"; } }
위 내용은 C# 7.0의 새로운 기능(빠른 미리 보기)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!