制約のない型パラメーターの注釈Unconstrained type parameter annotations
まとめSummary
値型または参照型に制約されない型パラメーターに対して、null 値を許容する注釈を許可 T?
します。Allow nullable annotations for type parameters that are not constrained to value types or reference types: T?
.
static T? FirstOrDefault<T>(this IEnumerable<T> collection) { ... }
?
注釈?
annotation
C# 8 では、注釈は、 ?
値型または参照型に明示的に制約された型パラメーターにのみ適用できます。In C#8, ?
annotations could only be applied to type parameters that were explicitly constrained to value types or reference types.
C# 9 では、 ?
制約に関係なく、すべての型パラメーターに注釈を適用できます。In C#9, ?
annotations can be applied to any type parameter, regardless of constraints.
型パラメーターが値型に明示的に制約されていない限り、注釈はコンテキスト内でのみ適用でき #nullable enable
ます。Unless a type parameter is explicitly constrained to value types, annotations can only be applied within a #nullable enable
context.
型パラメーター T
が参照型に代入される場合、は T?
その参照型の null 許容のインスタンスを表します。If a type parameter T
is substituted with a reference type, then T?
represents a nullable instance of that reference type.
var s1 = new string[0].FirstOrDefault(); // string? s1
var s2 = new string?[0].FirstOrDefault(); // string? s2
T
が値型に置き換えられた場合、は T?
のインスタンスを表し T
ます。If T
is substituted with a value type, then T?
represents an instance of T
.
var i1 = new int[0].FirstOrDefault(); // int i1
var i2 = new int?[0].FirstOrDefault(); // int? i2
T
が注釈付きの型に置き換えられる場合 U?
、は T?
ではなく注釈付きの型を表し U?
U??
ます。If T
is substituted with an annotated type U?
, then T?
represents the annotated type U?
rather than U??
.
var u1 = new U[0].FirstOrDefault(); // U? u1
var u2 = new U?[0].FirstOrDefault(); // U? u2
T
が型に置き換えられた場合、は、 U
T?
U?
コンテキスト内であってもを表し #nullable disable
ます。If T
is substituted with a type U
, then T?
represents U?
, even within a #nullable disable
context.
#nullable disable
var u3 = new U[0].FirstOrDefault(); // U? u3
戻り値の場合、 T?
はに相当します。 [MaybeNull]T
引数値の場合、 T?
はに相当 [AllowNull]T
します。For return values, T?
is equivalent to [MaybeNull]T
; for argument values, T?
is equivalent to [AllowNull]T
.
C# 8 でコンパイルされたアセンブリからインターフェイスをオーバーライドまたは実装する場合は、等価性が重要です。The equivalence is important when overriding or implementing interfaces from an assembly compiled with C#8.
public abstract class A
{
[return: MaybeNull] public abstract T F1<T>();
public abstract void F2<T>([AllowNull] T t);
}
public class B : A
{
public override T? F1<T>() where T : default { ... } // matches A.F1<T>()
public override void F2<T>(T? t) where T : default { ... } // matches A.F2<T>()
}
default
制約default
constraint
オーバーライドおよび明示的に実装されたジェネリックメソッドに明示的な制約句を含めることができない既存のコードとの互換性のために、 T?
オーバーライドまたは明示的に実装されたメソッドでは、が値型として扱われ Nullable<T>
T
ます。For compatibility with existing code where overridden and explicitly implemented generic methods could not include explicit constraint clauses, T?
in an overridden or explicitly implemented method is treated as Nullable<T>
where T
is a value type.
参照型に制約された型パラメーターの注釈を許可するために、C# 8 で where T : class
where T : struct
は、オーバーライドまたは明示的に実装されたメソッドに対して明示的および制約を許可しています。To allow annotations for type parameters constrained to reference types, C#8 allowed explicit where T : class
and where T : struct
constraints on the overridden or explicitly implemented method.
class A1
{
public virtual void F1<T>(T? t) where T : struct { }
public virtual void F1<T>(T? t) where T : class { }
}
class B1 : A1
{
public override void F1<T>(T? t) /*where T : struct*/ { }
public override void F1<T>(T? t) where T : class { }
}
参照型または値型に制約されない型パラメーターの注釈を許可するために、C# 9 では新しい制約を使用でき where T : default
ます。To allow annotations for type parameters that are not constrained to reference types or value types, C#9 allows a new where T : default
constraint.
class A2
{
public virtual void F2<T>(T? t) where T : struct { }
public virtual void F2<T>(T? t) { }
}
class B2 : A2
{
public override void F2<T>(T? t) /*where T : struct*/ { }
public override void F2<T>(T? t) where T : default { }
}
default
メソッドのオーバーライドまたは明示的な実装に対して以外の制約を使用すると、エラーになります。It is an error to use a default
constraint other than on a method override or explicit implementation.
default
オーバーライドまたはインターフェイスメソッドの対応する型パラメーターが参照型または値型に制限されている場合、制約を使用するとエラーになります。It is an error to use a default
constraint when the corresponding type parameter in the overridden or interface method is constrained to a reference type or value type.