C# 8.0的计划特性
2021-01-23 20:12
标签:attribute isa contain 接下来 obj ant The new cas
虽然现在C# 7才发布不久,并且新的版本和特性还在增加中,但是C# 8.0已经为大家公开了一些未来可能出现的新特性。 *注:以下特性只是计划,可能在将来的正式版本会有一些差异 该特性其实本来计划在C#7.x中就引入,但是却被推迟到了下一个版本中。目的是为了避免引用为null的时候而导致的错误。 其核心思想是允许变量类型定义指定是否可以为它们分配空值: 此时当申明可为nullable的对象赋值为null的时候,编译器就不会提示警告。 records是一个新的语法糖,它简化了原来创建简单类的过程,通过一条语句就可以创建出一个标准的C# 类。 例如下面的代码: 它相对于原来的写法是: 上面的代码段可以看出,该类具有只读属性和初始化它们的构造函数。它实现值的比较,并且重写了GetHashCode,以便在基于哈希的集合中使用,如Dictionary 和 Hashtable。 同时我们还看到在倒数第二个方法是一个解构的方法,它允许我们将Record所创建的对象进行解构为一个元组(关于解构的特性,可以参加C#7.0的特性) 最后的一个With方法可以供我们创建一个不同属性值的Sword副本对象。 当然,对于With的方法,C# 也提供了一个语法糖写法: 在以往的C# 语法中,我们都知道一个Interface只能够申明方法体,却不能对其进行实现: 按照以往的写法,我们一般是尝试写一些抽象类来作为替代实现: 但在C# 8.0中可能引入接口的方法实现功能。 C# 目前是已经支持了迭代器( iterators ) 和 异步方法。在C#8.0中打算结合现有的两者,推出异步的迭代器,它将基于异步的 IEnumerable 和 IEnumerator 接口: 此外,使用异步迭代器还需要IDisposable接口的异步版本: 接下来,在使用的时候,可能看上去就像下面这样: 当然,这个写法对我们C#的开发人员来说可能还不是太眼熟,因为在传统的迭代器写法上,我们已经习惯了Foreach的写法,因此对于异步迭代器来说,它也会存在对应的一个foreach版本,就如同下面这样: 这个特性可能相对来说就比较有趣了,它允许我们使用简短的语法来定义一个区间值,比如: 这样就产生了一个表示已声明范围的结构: 在实际的应用过程中,我们可以这样来使用它: 这个特性看上去果然非常的good。 对泛型特性的支持将为需要类型作为参数的属性提供更好的语法。目前,只能使用以下语法将类型传递给特性: 当有了泛型特性之后,我们可以尝试这样做: 在C# 7.x中引入了default 默认值和解构的概念。在C# 8中将实现两者的共同作用。 要为C#7中的元组的所有成员分配默认值,必须使用元组赋值语法: 通过支持解构语法中的默认文字,以下语法也可以实现相同的功能: 在C#5中,引入了CallerMemberName, CallerFilePath and CallerLineNumber特性,方便我们能够获取到有关调用方法的一些信息。 就像CallerMemberName在INotifyPropertyChanged中的应用,对于WPF开发的童鞋就在熟悉不过了: 在C#8中可能会引入一个叫做CallerArgumentExpression的特性,它捕获调用方法中的参数: 这可能也将成为将来常用的一个新特性,它将更加简化在申明时候的类型推断。 比如以往我们申明一个对象是这个样子的: 但是在C#8中,将简化成这样: Over: 当然距离C#8真是发布可能还要等一段时间,期间可能也会增加一些其他的特性,真正的体验效果还是一起期待8.0的发布吧 C# 8.0的计划特性 标签:attribute isa contain 接下来 obj ant The new cas 原文地址:https://www.cnblogs.com/lonelyxmas/p/12065786.html1.Nullable Reference Types
1 IWeapon? canBeNull;
2 IWeapon cantBeNull;
canBeNull =
null
;
// no warning
cantBeNull =
null
;
// warning
cantBeNull = canBeNull;
// warning
canBeNull.Repair();
// warning
cantBeNull.Repair();
// no warning
if
(canBeNull !=
null
) {
cantBeNull.Repair();
// no warning
}
2.Records
public
class
Sword(
int
Damage,
int
Durability);
public
class
Sword : IEquatable
{
public
int
Damage {
get
; }
public
int
Durability {
get
; }
public
Sword(
int
Damage,
int
Durability)
{
this
.Damage = Damage;
this
.Durability = Durability;
}
public
bool
Equals(Sword other)
{
return
Equals(Damage, other.Damage) && Equals(Durability, other.Durability);
}
public
override
bool
Equals(
object
other)
{
return
(other
as
Sword)?.Equals(
this
) ==
true
;
}
public
override
int
GetHashCode()
{
return
(Damage.GetHashCode() * 17 + Durability.GetHashCode());
}
public
void
Deconstruct(
out
int
Damage,
out
int
Durability)
{
Damage =
this
.Damage;
Durability =
this
.Durability;
}
public
Sword With(
int
Damage =
this
.Damage,
int
Durability =
this
.Durability) =>
new
Sword(Damage, Durability);
}
var
(damage, durability) = sword;
var
(damage, durability) = sword;
var
strongerSword = sword with { Damage = 8 };
3.Default Interface Methods
interface
ISample
{
void
M1();
// allowed
void
M2() => Console.WriteLine(
"ISample.M2"
);
// not allowed
}
abstract
class
SampleBase
{
public
abstract
void
M1();
public
void
M2() => Console.WriteLine(
"SampleBase.M2"
);
}
4.Asynchronous Streams
public
interface
IAsyncEnumerable
out
T>
{
IAsyncEnumerator
}
public
interface
IAsyncEnumerator
out
T> : IAsyncDisposable
{
Task
bool
> MoveNextAsync();
T Current {
get
; }
}
public
interface
IAsyncDisposable
{
Task DisposeAsync();
}
var
enumerator = enumerable.GetAsyncEnumerator();
try
{
while
(await enumerator.WaitForNextAsync())
{
while
(
true
)
{
Use(enumerator.Current);
}
}
}
finally
{
await enumerator.DisposeAsync();
}
foreach
await (
var
item
in
enumerable)
{
Use(item);
}
async IAsyncEnumerable
int
> AsyncIterator()
{
try
{
for
(
int
i = 0; i
{
yield await GetValueAsync(i);
}
}
finally
{
await HandleErrorAsync();
}
}
5.Ranges
var
range = 1..5;
struct
Range : IEnumerable
int
>
{
public
Range(
int
start,
int
end);
public
int
Start {
get
; }
public
int
End {
get
; }
public
StructRangeEnumerator GetEnumerator();
// overloads for Equals, GetHashCode...
}
Span
this
[Range range]
{
get
{
return
((Span
this
).Slice(start: range.Start, length: range.End - range.Start);
}
}
foreach
(
var
index
in
min..max)
{
// process values
}
switch
(value)
{
case
1..5:
// value in range
break
;
}
6.Generic Attributes
public
class
TypedAttribute : Attribute
{
public
TypedAttribute(Type type)
{
// ...
}
}
public
class
TypedAttribute
{
public
TypedAttribute()
{
// ...
}
}
public
TypedAttribute(T value)
{
// ...
}
7.Default Literal in Deconstruction
(
int
x,
int
y) = (
default
,
default
);
(
int
x,
int
y) =
default
;
8.Caller Argument Expression
class
ViewModel : INotifyPropertyChanged
{
public
event
PropertyChangedEventHandler PropertyChanged;
private
void
OnPropertyChanged([CallerMemberName]
string
propertyName =
null
)
{
PropertyChanged?.Invoke(
this
,
new
PropertyChangedEventArgs(propertyName));
}
private
int
property;
public
int
Property
{
get
{
return
property; }
set
{
if
(value != property)
{
property = value;
OnPropertyChanged();
}
}
}
}
public
Validate(
int
[] array, [CallerArgumentExpression(
"array"
)]
string
arrayExpression =
null
)
{
if
(array ==
null
)
{
throw
new
ArgumentNullException(nameof(array), $
"{arrayExpression} was null."
);
}
if
(array.Length == 0)
{
throw
new
ArgumentException($
"{arrayExpression} was empty."
, nameof(array));
}
}
9.Target-typed new Expression
Dictionary
string
,
string
> dictionary =
new
Dictionary
string
,
string
>();
// without var keyword
var
dictionary =
new
Dictionary
string
,
string
>();
// with var keyword
class
DictionaryWrapper
{
private
Dictionary
string
,
string
> dictionary =
new
();
// ...
}