Uwaga
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Ten dokument wymienia znane zmiany powodujące niekompatybilność w Roslyn od ogólnego wydania platformy .NET 6 (wersja zestawu .NET SDK 6.0.100) do ogólnego wydania platformy .NET 7 (wersja zestawu .NET SDK 7.0.100).
Wszystkie lokalne zmienne typów ograniczonych są niedozwolone w metodach asynchronicznych
Wprowadzono w programie Visual Studio 2022 w wersji 17.6p1
Typy z lokalnymi ograniczeniami są niedozwolone w metodach asynchronicznych. Jednak we wcześniejszych wersjach kompilator nie zauważył niektórych niejawnie zadeklarowanych ustawień lokalnych. Na przykład w foreach
instrukcjach lub using
dekonstrukcji.
Teraz takie zmienne lokalne, zadeklarowane niejawnie, są również niedozwolone.
ref struct RefStruct { public void Dispose() { } }
public class C
{
public async Task M()
{
RefStruct local = default; // disallowed
using (default(RefStruct)) { } // now disallowed too ("error CS9104: A using statement resource of this type cannot be used in async methods or async lambda expressions")
}
}
Zobacz https://github.com/dotnet/roslyn/pull/66264
Wskaźniki muszą zawsze znajdować się w niebezpiecznych kontekstach.
Wprowadzono w programie Visual Studio 2022 w wersji 17.6
We wcześniejszych zestawach SDK kompilator od czasu do czasu zezwalałby na lokalizacje, w których można odwoływać się do wskaźników, bez jawnego oznaczania tej lokalizacji jako niebezpiecznej.
Teraz modyfikator unsafe
musi być obecny.
Na przykład using Alias = List<int*[]>;
należy zmienić wartość na using unsafe Alias = List<int*[]>;
legalną.
Użycie, takie jak void Method(Alias a) ...
należy zmienić na unsafe void Method(Alias a) ...
.
Reguła jest bezwarunkowa, z wyjątkiem using
deklaracji aliasów (które nie zezwalały na unsafe
modyfikator przed C# 12).
W przypadku using
deklaracji reguła ma zastosowanie tylko wtedy, gdy wersja języka zostanie wybrana jako C# 12 lub nowsza.
System.TypedReference uznawany za zarządzany
Wprowadzono w programie Visual Studio 2022 w wersji 17.6
W przyszłości System.TypedReference
typ jest uważany za zarządzany.
unsafe
{
TypedReference* r = null; // warning: This takes the address of, gets the size of, or declares a pointer to a managed type
var a = stackalloc TypedReference[1]; // error: Cannot take the address of, get the size of, or declare a pointer to a managed type
}
Błędy bezpieczeństwa dla ref nie wpływają na konwersję wyrażenia lambda na delegata
Wprowadzono w programie Visual Studio 2022 w wersji 17.5
Błędy bezpieczeństwa ref zgłoszone w ciele wyrażenia lambda nie mają już wpływu na to, czy wyrażenie lambda może być przekształcane na typ delegata. Ta zmiana może mieć wpływ na rozwiązanie przeciążenia.
W poniższym przykładzie wywołanie M(x => ...)
jest niejednoznaczne w programie Visual Studio 17.5, ponieważ zarówno M(D1)
, jak i M(D2)
są teraz uznawane za możliwe do zastosowania, mimo że wywołanie F(ref x, ref y)
w treści lambdy spowoduje powstanie bezpieczeństwa odwołania z M(D1)
(zobacz przykłady w d1
i d2
dla porównania). Wcześniej wywołanie było powiązane jednoznacznie z M(D2)
ponieważ przeciążenie M(D1)
zostało uznane za nieodpowiednie.
using System;
ref struct R { }
delegate R D1(R r);
delegate object D2(object o);
class Program
{
static void M(D1 d1) { }
static void M(D2 d2) { }
static void F(ref R x, ref Span<int> y) { }
static void F(ref object x, ref Span<int> y) { }
static void Main()
{
// error CS0121: ambiguous between: 'M(D1)' and 'M(D2)'
M(x =>
{
Span<int> y = stackalloc int[1];
F(ref x, ref y);
return x;
});
D1 d1 = x1 =>
{
Span<int> y1 = stackalloc int[1];
F(ref x1, ref y1); // error CS8352: 'y2' may expose referenced variables
return x1;
};
D2 d2 = x2 =>
{
Span<int> y2 = stackalloc int[1];
F(ref x2, ref y2); // ok: F(ref object x, ref Span<int> y)
return x2;
};
}
}
Aby obejść zmiany rozpoznawania przeciążenia, użyj jawnych typów dla parametrów lambda lub delegata.
// ok: M(D2)
M((object x) =>
{
Span<int> y = stackalloc int[1];
F(ref x, ref y); // ok: F(ref object x, ref Span<int> y)
return x;
});
Surowe interpolacje ciągów znaków na początku wiersza.
Wprowadzono w programie Visual Studio 2022 w wersji 17.5
W wersji .NET SDK 7.0.100 lub starszej błędnie były dozwolone następujące elementy.
var x = $"""
Hello
{1 + 1}
World
""";
Narusza to regułę, że zawartość wierszy (w tym miejsce rozpoczęcia interpolacji) musi zaczynać się od tego samego odstępu co ostatni """;
wiersz. Teraz wymagane jest, aby powyższe elementy zostały zapisane jako:
var x = $"""
Hello
{1 + 1}
World
""";
Wnioskowany typ delegata dla metod zawiera domyślne wartości parametrów i params
modyfikator
Wprowadzono w programie Visual Studio 2022 w wersji 17.5
W wersji .NET SDK 7.0.100 lub starszej typy delegatów wywnioskowane z metod ignorowały domyślne wartości parametrów i modyfikatory params
, jak pokazano w poniższym kodzie.
void Method(int i = 0, params int[] xs) { }
var action = Method; // System.Action<int, int[]>
DoAction(action, 1); // ok
void DoAction(System.Action<int, int[]> a, int p) => a(p, new[] { p });
W zestawie .NET SDK 7.0.200 lub nowszym takie metody są wnioskowane jako anonimowe syntetyzowane typy delegatów z tymi samymi domyślnymi wartościami parametrów i params
modyfikatorami.
Ta zmiana może przerwać powyższy kod, jak pokazano poniżej:
void Method(int i = 0, params int[] xs) { }
var action = Method; // delegate void <anonymous delegate>(int arg1 = 0, params int[] arg2)
DoAction(action, 1); // error CS1503: Argument 1: cannot convert from '<anonymous delegate>' to 'System.Action<int, int[]>'
void DoAction(System.Action<int, int[]> a, int p) => a(p, new[] { p });
Więcej informacji na temat tej zmiany można uzyskać w skojarzonej propozycji.
W celu analizy jednoznacznego przypisania wywołania funkcji lokalnych asynchronicznych nie są już traktowane jako oczekujące na wykonanie.
Wprowadzono w programie Visual Studio 2022 w wersji 17.5
Do celów analizy jednoznacznego przypisania, wywołania lokalnej funkcji asynchronicznej nie są już traktowane jako czekania, z tego powodu funkcja lokalna nie jest uważana za w pełni wykonaną. Zobacz https://github.com/dotnet/roslyn/issues/43697 dla uzasadnienia.
Poniższy kod zgłosi teraz określony błąd przypisania:
public async Task M()
{
bool a;
await M1();
Console.WriteLine(a); // error CS0165: Use of unassigned local variable 'a'
async Task M1()
{
if ("" == String.Empty)
{
throw new Exception();
}
else
{
a = true;
}
}
}
INoneOperation
węzły atrybutów są teraz IAttributeOperation
węzłami.
Wprowadzono w programie Visual Studio 2022 w wersji 17.5, .NET SDK w wersji 7.0.200
W poprzednich wersjach kompilatora IOperation
drzewo atrybutu zostało zakorzenione w węźle INoneOperation
.
Dodaliśmy natywną obsługę atrybutów, co oznacza, że korzeń drzewa jest teraz elementem IAttributeOperation
. Niektóre analizatory, w tym starsze wersje analizatorów zestawu .NET SDK, nie spodziewają się tego kształtu drzewa składniowego i będą niepoprawnie ostrzegać (lub potencjalnie nie ostrzegać) po jego napotkaniu. Obejścia tego problemu są następujące:
- Zaktualizuj wersję analizatora, jeśli to możliwe. Jeśli używasz zestawu .NET SDK lub starszych wersji microsoft.CodeAnalysis.FxCopAnalyzers, zaktualizuj do wersji Microsoft.CodeAnalysis.NetAnalyzers 7.0.0-preview1.22464.1 lub nowszej.
- Pomijanie wszelkich wyników fałszywie dodatnich z analizatorów do momentu ich zaktualizowania przy użyciu wersji, która uwzględnia tę zmianę.
Testy typów dla ref
struktur nie są obsługiwane.
Wprowadzono w programie Visual Studio 2022 w wersji 17.4
ref
Gdy typ struktury jest używany w operatorach "is" lub "as", w niektórych scenariuszach kompilator wcześniej zgłaszał błędne ostrzeżenie informujące, że test typu zawsze kończy się niepowodzeniem w czasie wykonywania, pomijając faktyczne sprawdzenie typu, co prowadziło do nieprawidłowego zachowania. Jeśli możliwe było nieprawidłowe zachowanie w czasie wykonywania, kompilator utworzy teraz błąd.
ref struct G<T>
{
public void Test()
{
if (this is G<int>) // Will now produce an error, used to be treated as always `false`.
{
Nieużywane wyniki zmiennej lokalnej odwołania są dereferencjami.
Wprowadzono w programie Visual Studio 2022 w wersji 17.4
Gdy zmienna lokalna ref
jest przywoływana przez wartość, ale wynik nie jest używany (na przykład przypisywany do odrzucenia), wynik został wcześniej zignorowany. Kompilator wyłuszy teraz tę lokalną zmienną, ubezpieczając się, że wszelkie skutki uboczne są obserwowane.
ref int local = Unsafe.NullRef<int>();
_ = local; // Will now produce a `NullReferenceException`
Typy nie mogą być nazwane scoped
Wprowadzono w programie Visual Studio 2022 w wersji 17.4. Począwszy od języka C# 11, typy nie mogą mieć nazwy scoped
. Kompilator zgłosi błąd dla wszystkich takich nazw typów. Aby obejść ten problem, nazwa typu i wszystkie użycia muszą zostać zaznaczone za pomocą znacznika @
.
class scoped {} // Error CS9056
class @scoped {} // No error
ref scoped local; // Error
ref scoped.nested local; // Error
ref @scoped local2; // No error
Zostało to zrobione, ponieważ scoped
jest teraz modyfikatorem deklaracji zmiennych i jest zarezerwowany po ref
w typie ref.
Typy nie mogą być nazwane file
Wprowadzono w programie Visual Studio 2022 w wersji 17.4. Począwszy od języka C# 11, typy nie mogą mieć nazwy file
. Kompilator zgłosi błąd dla wszystkich takich nazw typów. Aby obejść ten problem, nazwa typu i wszystkie użycia muszą zostać zaznaczone za pomocą znacznika @
.
class file {} // Error CS9056
class @file {} // No error
Zostało to zrobione, ponieważ file
jest teraz modyfikatorem deklaracji typów.
Więcej informacji na temat tej zmiany można znaleźć w skojarzonym zgłoszeniu csharplang.
Wymagane spacje w dyrektywach zakresu #line
Wprowadzono w zestawie .NET SDK 6.0.400, Visual Studio 2022 w wersji 17.3.
Gdy dyrektywa #line
span została wprowadzona w C# 10, nie wymagała żadnego szczególnego odstępu.
Na przykład będzie to prawidłowe: #line(1,2)-(3,4)5"file.cs"
.
W programie Visual Studio 17.3 kompilator wymaga spacji przed pierwszym nawiasem, offsetem znaku i nazwą pliku.
Dlatego powyższy przykład nie zostanie poprawnie zinterpretowany, dopóki nie zostaną dodane spacje: #line (1,2)-(3,4) 5 "file.cs"
.
Sprawdzone operatory w System.IntPtr i System.UIntPtr
Wprowadzono w .NET SDK w wersji 7.0.100, Visual Studio 2022 wersji 17.3.
Gdy platforma obsługuje wartości liczboweIntPtr
i UIntPtr
typy (wskazywane przez obecność System.Runtime.CompilerServices.RuntimeFeature.NumericIntPtr
) wbudowane operatory z nint
i nuint
mają zastosowanie do tych typów bazowych.
Oznacza to, że na takich platformach IntPtr
i UIntPtr
mają wbudowane checked
operatory, które mogą teraz generować wyjątek w przypadku wystąpienia przepełnienia.
IntPtr M(IntPtr x, int y)
{
checked
{
return x + y; // may now throw
}
}
unsafe IntPtr M2(void* ptr)
{
return checked((IntPtr)ptr); // may now throw
}
Możliwe obejścia to:
- Określanie
unchecked
kontekstu - Obniżanie do platformy/serwera TFM bez typów liczbowych
IntPtr
/UIntPtr
Ponadto niejawne konwersje między IntPtr
/UIntPtr
i innymi typami liczbowymi są traktowane jako standardowe konwersje na takich platformach. Może to mieć wpływ na rozwiązanie przeciążenia w niektórych przypadkach.
Te zmiany mogą spowodować zmianę zachowania, jeśli kod użytkownika był zależny od wyjątków przepełnienia w nieznakowanym kontekście lub jeśli nie spodziewał się wyjątków przepełnienia w zaznaczonym kontekście. Analizator został dodany w wersji 7.0 , aby pomóc wykryć takie zmiany behawioralne i podjąć odpowiednie działania. Analizator utworzy diagnostykę potencjalnych zmian behawioralnych, które domyślnie mają ważność informacji, ale mogą zostać uaktualnione do ostrzeżeń za pośrednictwem pliku editorconfig.
Dodanie elementów System.UIntPtr i System.Int32
Wprowadzono w .NET SDK w wersji 7.0.100, Visual Studio 2022 wersji 17.3.
Gdy platforma obsługuje typy wartości liczboweIntPtr
i UIntPtr
, wskazywane przez obecność System.Runtime.CompilerServices.RuntimeFeature.NumericIntPtr
, operator +(UIntPtr, int)
zdefiniowany w System.UIntPtr
nie może być już używany.
Zamiast tego dodanie wyrażeń typów System.UIntPtr
i System.Int32
powoduje wystąpienie błędu:
UIntPtr M(UIntPtr x, int y)
{
return x + y; // error: Operator '+' is ambiguous on operands of type 'nuint' and 'int'
}
Możliwe obejścia to:
-
UIntPtr.Add(UIntPtr, int)
Użyj metody :UIntPtr.Add(x, y)
- Zastosuj rzutowanie niezweryfikowane do typu
nuint
na drugi operand:x + unchecked((nuint)y)
Operator Nameof w atrybucie metody lub lokalnej funkcji
Wprowadzono w zestawie .NET SDK 6.0.400, Visual Studio 2022 w wersji 17.3.
Jeśli wersja języka to C# 11 lub nowsza, nameof
operator w atrybucie na metodzie wprowadza parametry typu tej metody w jego zasięg. Dotyczy to również funkcji lokalnych.
Operatory nameof
w atrybucie na metodzie, jej parametrach typu lub innych parametrach umożliwiają dostęp do tych parametrów w obrębie metody. To samo dotyczy funkcji lokalnych, lambdów, delegatów i indeksatorów.
Na przykład będą to błędy:
class C
{
class TParameter
{
internal const string Constant = """";
}
[MyAttribute(nameof(TParameter.Constant))]
void M<TParameter>() { }
}
class C
{
class parameter
{
internal const string Constant = """";
}
[MyAttribute(nameof(parameter.Constant))]
void M(int parameter) { }
}
Możliwe obejścia to:
- Zmień nazwę parametru lub parametru typu, aby uniknąć cieniowania nazwy z zakresu zewnętrznego.
- Zamiast operatora
nameof
użyj literału ciągu.
Nie można zwrócić parametru out przez odwołanie
Wprowadzono w .NET SDK w wersji 7.0.100, Visual Studio 2022 wersji 17.3.
W wersji językowej C# 11 lub nowszej albo w wersji .NET 7.0 lub nowszej nie można zwrócić parametru out
przez odwołanie.
static ref T ReturnOutParamByRef<T>(out T t)
{
t = default;
return ref t; // error CS8166: Cannot return a parameter by reference 't' because it is not a ref parameter
}
Możliwe obejścia to:
Użyj
System.Diagnostics.CodeAnalysis.UnscopedRefAttribute
do oznaczenia odwołania jako niezakresowego.static ref T ReturnOutParamByRef<T>([UnscopedRef] out T t) { t = default; return ref t; // ok }
Zmień sygnaturę metody, aby przekazać parametr przez
ref
.static ref T ReturnRefParamByRef<T>(ref T t) { t = default; return ref t; // ok }
Metoda instancyjna w strukturze ref może przechwytywać nieokreślone parametry ref
Wprowadzono w zestawie .NET SDK 7.0.100, Visual Studio 2022 w wersji 17.4.
Zakłada się, że w wersji językowej C# 11 lub nowszej albo z platformą .NET 7.0 lub nowszą wywołanie metody instancji ref struct
służy do przechwycenia niezakresowych parametrów ref
lub in
.
R<int> Use(R<int> r)
{
int i = 42;
r.MayCaptureArg(ref i); // error CS8350: may expose variables referenced by parameter 't' outside of their declaration scope
return r;
}
ref struct R<T>
{
public void MayCaptureArg(ref T t) { }
}
Możliwe obejście, jeśli parametr ref
lub in
nie jest przechwytywany w metodzie instancji ref struct
, polega na zadeklarowaniu parametru jako scoped ref
lub scoped in
.
R<int> Use(R<int> r)
{
int i = 42;
r.CannotCaptureArg(ref i); // ok
return r;
}
ref struct R<T>
{
public void CannotCaptureArg(scoped ref T t) { }
}
Analiza ucieczki powrotnej struktury metody zależy od ucieczki ref argumentów ref
Wprowadzono w zestawie .NET SDK 7.0.100, Visual Studio 2022 w wersji 17.4.
W wersji językowej C# 11 lub nowszej albo z platformą .NET 7.0 lub nowszą ref struct
zwracaną z wywołania metody jako wartość zwracaną lub w out
parametrach jest bezpieczna do ucieczki tylko wtedy, gdy wszystkie ref
argumenty i in
do wywołania metody są ref-safe-to-escape.
Argumenty in
mogą zawierać niejawne wartości parametrów domyślnych.
ref struct R { }
static R MayCaptureArg(ref int i) => new R();
static R MayCaptureDefaultArg(in int i = 0) => new R();
static R Create()
{
int i = 0;
// error CS8347: Cannot use a result of 'MayCaptureArg(ref int)' because it may expose
// variables referenced by parameter 'i' outside of their declaration scope
return MayCaptureArg(ref i);
}
static R CreateDefault()
{
// error CS8347: Cannot use a result of 'MayCaptureDefaultArg(in int)' because it may expose
// variables referenced by parameter 'i' outside of their declaration scope
return MayCaptureDefaultArg();
}
Możliwe obejście, jeśli argument ref
lub in
nie jest przechwytywany w zwracanej wartości ref struct
, to zadeklarowanie parametru jako scoped ref
lub scoped in
.
static R CannotCaptureArg(scoped ref int i) => new R();
static R Create()
{
int i = 0;
return CannotCaptureArg(ref i); // ok
}
ref
argument ref struct
uważany za nieobjęty zakresem w __arglist
Wprowadzono w zestawie .NET SDK 7.0.100, Visual Studio 2022 w wersji 17.4.
W wersji językowej C# 11 lub nowszej albo w wersji .NET 7.0 lub nowszej referencja z ref
do typu ref struct
jest uznawana za niezakresowe odwołanie, gdy jest przekazywane jako argument do __arglist
.
ref struct R { }
class Program
{
static void MayCaptureRef(__arglist) { }
static void Main()
{
var r = new R();
MayCaptureRef(__arglist(ref r)); // error: may expose variables outside of their declaration scope
}
}
Operator niepodpisanego przesunięcia w prawo
Wprowadzono w zestawie .NET SDK 6.0.400, Visual Studio 2022 w wersji 17.3. Język dodał obsługę operatora "Niepodpisane przesunięcie w prawo" (>>>
).
Spowoduje to wyłączenie możliwości korzystania z metod implementowania zdefiniowanych przez użytkownika operatorów "Unsigned Right Shift" jako zwykłych metod.
Istnieje na przykład istniejąca biblioteka opracowana w niektórych językach (innym niż VB lub C#), która uwidacznia operator zdefiniowany przez użytkownika "Niepodpisane przesunięcie w prawo" dla typu C1
.
Poniższy kod, który kiedyś kompilował się pomyślnie:
static C1 Test1(C1 x, int y) => C1.op_UnsignedRightShift(x, y); //error CS0571: 'C1.operator >>>(C1, int)': cannot explicitly call operator or accessor
Możliwe obejście polega na przełączeniu się na korzystanie z operatora >>>
:
static C1 Test1(C1 x, int y) => x >>> y;
Moduł wyliczający Foreach jako struktura ref
Wprowadzono w zestawie .NET SDK 6.0.300, Visual Studio 2022 w wersji 17.2. Użycie typu wyliczającego ref struct zgłasza błąd, jeśli wersja języka jest ustawiona na 7.3 lub wcześniejszą.
To naprawia usterkę polegającą na tym, że funkcja była obsługiwana w nowszych kompilatorach przeznaczonych dla wersji języka C# przed jej obsługą.
Możliwe obejścia to:
- Zmień typ
ref struct
na typstruct
lubclass
. - Uaktualnij
<LangVersion>
element do wersji 7.3 lub nowszej.
Async foreach
preferuje metodologię wzorcową DisposeAsync
nad bezpośrednią implementacją interfejsu IAsyncDisposable.DisposeAsync()
Wprowadzono w zestawie .NET SDK 6.0.300, Visual Studio 2022 w wersji 17.2. Asynchroniczna foreach
preferuje powiązanie przy użyciu metody opartej na wzorcu DisposeAsync()
zamiast IAsyncDisposable.DisposeAsync()
.
Na przykład DisposeAsync()
zostanie wybrany zamiast metody IAsyncEnumerator<int>.DisposeAsync()
na AsyncEnumerator
:
await foreach (var i in new AsyncEnumerable())
{
}
struct AsyncEnumerable
{
public AsyncEnumerator GetAsyncEnumerator() => new AsyncEnumerator();
}
struct AsyncEnumerator : IAsyncDisposable
{
public int Current => 0;
public async ValueTask<bool> MoveNextAsync()
{
await Task.Yield();
return false;
}
public async ValueTask DisposeAsync()
{
Console.WriteLine("PICKED");
await Task.Yield();
}
ValueTask IAsyncDisposable.DisposeAsync() => throw null; // no longer picked
}
Ta zmiana naprawia naruszenie specyfikacji, gdy metoda publiczna DisposeAsync
jest widoczna w zadeklarowanym typie, natomiast implementacja jawnego interfejsu jest widoczna tylko przy użyciu odwołania do typu interfejsu.
Aby obejść ten błąd, usuń metodę opartą na DisposeAsync
wzorcu z typu.
Nie zezwalaj na użycie skonwertowanych stringów jako argumentu domyślnego
Wprowadzono w zestawie .NET SDK 6.0.300, Visual Studio 2022 w wersji 17.2. Kompilator języka C# akceptował niepoprawne domyślne wartości argumentów, które obejmowały konwersję odwołania stałej tekstowej, i emitował null
jako wartość zamiast wartości domyślnej określonej w źródle. W programie Visual Studio 17.2 staje się to błędem. Zobacz roslyn#59806.
Ta zmiana naprawia naruszenie specyfikacji w kompilatorze. Argumenty domyślne muszą być stałymi czasu kompilacji. Poprzednie wersje zezwalały na następujący kod:
void M(IEnumerable<char> s = "hello")
Poprzednia deklaracja wymagała konwersji z string
na IEnumerable<char>
. Kompilator zezwolił na tę konstrukcję i emituje null
jako wartość argumentu. Powyższy kod generuje błąd kompilatora rozpoczynający się w wersji 17.2.
Aby obejść tę zmianę, możesz wprowadzić jedną z następujących zmian:
- Zmień typ parametru, aby konwersja nie jest wymagana.
- Aby przywrócić poprzednie zachowanie, zmień wartość domyślnego argumentu na
null
.
Kontekstowe słowo kluczowe var
jako jawnie określony typ zwracania lambda
Wprowadzono w zestawie .NET SDK 6.0.200, Visual Studio 2022 w wersji 17.1. Kontekstowe słowo kluczowe var nie może być używane jako jawny typ zwracany przez lambda.
Ta zmiana umożliwia potencjalne przyszłe funkcje , zapewniając, że var
pozostanie naturalnym typem zwracanego wyrażenia lambda.
Ten błąd może wystąpić, jeśli masz typ o nazwie var
i definiujesz wyrażenie lambda przy użyciu jawnego typu zwracanego var
(typ).
using System;
F(var () => default); // error CS8975: The contextual keyword 'var' cannot be used as an explicit lambda return type
F(@var () => default); // ok
F(() => default); // ok: return type is inferred from the parameter to F()
static void F(Func<var> f) { }
public class var
{
}
Obejścia obejmują następujące zmiany:
- Użyj typu zwracanego
@var
. - Usuń jawny typ zwracany, żeby kompilator określał typ zwracany.
Procedury obsługi ciągów interpolowanych i inicjowanie indeksatora
Wprowadzono w zestawie .NET SDK 6.0.200, Visual Studio 2022 w wersji 17.1. Indeksatory, które przyjmują obsługę ciągów interpolowanych i wymagają odbiornika jako argumentu dla konstruktora, nie mogą być używane w inicjatorze obiektów.
Ta zmiana nie zezwala na sytuację brzegową, w której inicjator indeksatora używa obsługiwacza ciągów interpolowanych, a ten obsługiwacz przyjmuje odbiornik indeksatora jako parametr konstruktora. Przyczyną tej zmiany jest to, że ten scenariusz może spowodować uzyskanie dostępu do zmiennych, które nie zostały jeszcze zainicjowane. Rozważ taki przykład:
using System.Runtime.CompilerServices;
// error: Interpolated string handler conversions that reference
// the instance being indexed cannot be used in indexer member initializers.
var c = new C { [$""] = 1 };
class C
{
public int this[[InterpolatedStringHandlerArgument("")] CustomHandler c]
{
get => ...;
set => ...;
}
}
[InterpolatedStringHandler]
class CustomHandler
{
// The constructor of the string handler takes a "C" instance:
public CustomHandler(int literalLength, int formattedCount, C c) {}
}
Obejścia obejmują następujące zmiany:
- Usuń typ odbiorcy z procedury obsługi ciągów interpolowanych.
- Zmień argument na indeksator na
string
Nie można używać parametrów ani zwracać ref, readonly ref, in, out w metodach dostępnych tylko dla niezarządzanych wywołujących.
Wprowadzono w zestawie .NET SDK 6.0.200, Visual Studio 2022 w wersji 17.1.ref
/ref readonly
/in
/out
nie mogą być używane jako zwracane wartości/parametry metody oznaczonej UnmanagedCallersOnly
.
Ta zmiana jest poprawką błędów. Wartości zwracane i parametry nie są bezpośrednio mapowalne. Przekazywanie argumentów lub zwracanych wartości przez odwołanie może spowodować niezdefiniowane zachowanie. Żadna z następujących deklaracji nie zostanie skompilowana
using System.Runtime.InteropServices;
[UnmanagedCallersOnly]
static ref int M1() => throw null; // error CS8977: Cannot use 'ref', 'in', or 'out' in a method attributed with 'UnmanagedCallersOnly'.
[UnmanagedCallersOnly]
static ref readonly int M2() => throw null; // error CS8977: Cannot use 'ref', 'in', or 'out' in a method attributed with 'UnmanagedCallersOnly'.
[UnmanagedCallersOnly]
static void M3(ref int o) => throw null; // error CS8977: Cannot use 'ref', 'in', or 'out' in a method attributed with 'UnmanagedCallersOnly'.
[UnmanagedCallersOnly]
static void M4(in int o) => throw null; // error CS8977: Cannot use 'ref', 'in', or 'out' in a method attributed with 'UnmanagedCallersOnly'.
[UnmanagedCallersOnly]
static void M5(out int o) => throw null; // error CS8977: Cannot use 'ref', 'in', or 'out' in a method attributed with 'UnmanagedCallersOnly'.
Obejście polega na usunięciu modyfikatora przekazywania przez referencję.
Długość, liczba przyjmowana jako nieujemna we wzorcach
Wprowadzono w zestawie .NET SDK 6.0.200, Visual Studio 2022 w wersji 17.1.Length
oraz Count
właściwości typów zliczalnych i indeksowalnych przyjmuje się jako nieujemne dla celów analizy podsumpcji oraz wyczerpującej analizy wzorców i przełączników.
Te typy mogą być używane z indeksatorem Index i wzorcami list ukrytymi.
Właściwości Length
i Count
, mimo że typizowane jako int
, zakłada się, że nie są ujemne podczas analizowania wzorców. Rozważmy tę przykładową metodę:
string SampleSizeMessage<T>(IList<T> samples)
{
return samples switch
{
// This switch arm prevents a warning before 17.1, but will never happen in practice.
// Starting with 17.1, this switch arm produces a compiler error.
// Removing it won't introduce a warning.
{ Count: < 0 } => throw new InvalidOperationException(),
{ Count: 0 } => "Empty collection",
{ Count: < 5 } => "Too small",
{ Count: < 20 } => "reasonable for the first pass",
{ Count: < 100 } => "reasonable",
{ Count: >= 100 } => "fine",
};
}
void M(int[] i)
{
if (i is { Length: -1 }) {} // error: impossible under assumption of non-negative length
}
Przed 17.1, pierwsze ramię przełącznika, testowanie, czy Count
jest ujemne, było konieczne, aby uniknąć ostrzeżenia, że wszystkie możliwe wartości nie zostały objęte. Począwszy od wersji 17.1, pierwsze ramię przełącznika generuje błąd kompilatora. Obejście polega na usunięciu ramion przełącznika dodanych do nieprawidłowych przypadków.
Ta zmiana została wprowadzona w ramach dodawania wzorców listy. Reguły przetwarzania są bardziej spójne, jeśli każde użycie właściwości Length
lub Count
w kolekcji jest uznawane za nieujemne. Więcej informacji na temat zmiany w kwestii projektowania języka można znaleźć w dokumentacji.
Obejście polega na usunięciu ramion przełącznika z niemożliwymi do osiągnięcia warunkami.
Dodawanie inicjatorów pól do struktury wymaga jawnie zadeklarowanego konstruktora
Wprowadzono w .NET SDK 6.0.200, Visual Studio 2022 w wersji 17.1.struct
deklaracje typów z inicjalizatorami pól muszą zawierać jawnie zadeklarowany konstruktor. Ponadto wszystkie pola muszą być jednoznacznie przypisane w konstruktorach instancji struct
, które nie mają inicjalizatora : this()
, więc wszystkie wcześniej nieprzypisane pola muszą zostać przypisane za pomocą dodanego konstruktora lub inicjalizatorów pól. Zobacz dotnet/csharplang#5552, dotnet/roslyn#58581.
Istnieją dwa sposoby inicjowania zmiennej do jej wartości domyślnej w języku C#: new()
i default
. W przypadku klas różnica jest widoczna, ponieważ new
tworzy nowe wystąpienie i default
zwraca wartość null
. Różnica jest bardziej subtelna dla struktur, ponieważ w przypadku default
struktur funkcja zwraca wystąpienie z każdym polem/właściwością ustawioną na własną wartość domyślną. Dodaliśmy inicjatory pól dla struktur w języku C# 10. Inicjatory pól są wykonywane tylko wtedy, gdy jawnie zadeklarowany konstruktor jest uruchamiany. Co ważne, nie są one wykonywane podczas używania default
czy tworzenia tablicy o dowolnym struct
typie.
W wersji 17.0, jeśli istnieją inicjatory pól, ale nie zadeklarowane konstruktory, konstruktor bez parametrów jest syntetyzowany, który uruchamia inicjatory pól. Oznaczało to jednak, że dodanie lub usunięcie deklaracji konstruktora może mieć wpływ na to, czy konstruktor bez parametrów jest syntetyzowany, a w rezultacie może zmienić zachowanie klasy new()
.
Aby rozwiązać ten problem, w zestawie .NET SDK 6.0.200 (VS 17.1) kompilator nie syntetyzuje już konstruktora bez parametrów. Jeśli element struct
zawiera inicjatory pól i nie ma jawnych konstruktorów, kompilator generuje błąd. Jeśli element struct
zawiera inicjatory pól, musi zadeklarować konstruktor, ponieważ w przeciwnym razie inicjatory pól nigdy nie są wykonywane.
Ponadto wszystkie pola, które nie mają inicjatorów pól, muszą być przypisane w każdym struct
konstruktorze, chyba że konstruktor ma : this()
inicjator.
Przykład:
struct S // error CS8983: A 'struct' with field initializers must include an explicitly declared constructor.
{
int X = 1;
int Y;
}
Sposobem obejścia jest zadeklarowanie konstruktora. Jeśli pola nie zostały wcześniej nieprzypisane, ten konstruktor może i często będzie pustym konstruktorem bez parametrów:
struct S
{
int X = 1;
int Y;
public S() { Y = 0; } // ok
}
Specyfikatory formatu nie mogą zawierać nawiasów klamrowych
Wprowadzono w zestawie .NET SDK 6.0.200, Visual Studio 2022 w wersji 17.1. Specyfikatory formatu w ciągach interpolowanych nie mogą zawierać nawiasów klamrowych ({
lub }
). W poprzednich wersjach {{
był interpretowany jako znak ucieczki {
, a }}
jako znak ucieczki }
w specyfikatorze formatu. Teraz pierwszy }
znak w specyfikatorze formatu kończy interpolację, a dowolny {
znak jest błędem.
Dzięki temu przetwarzanie ciągów interpolowanych jest spójne z przetwarzaniem dla elementu System.String.Format
:
using System;
Console.WriteLine($"{{{12:X}}}");
//prints now: "{C}" - not "{X}}"
X
jest szesnastkowym zapisem wielkimi literami, a C
jest wartością szesnastkową liczby 12.
Rozwiązaniem jest usunięcie dodatkowych nawiasów klamrowych w łańcuchu formatującym.
Więcej informacji na temat tej zmiany można znaleźć w powiązanym zgłoszeniu roslyn.
Typy nie mogą być nazwane required
Wprowadzono w programie Visual Studio 2022 w wersji 17.3. Począwszy od języka C# 11, typy nie mogą mieć nazwy required
. Kompilator zgłosi błąd dla wszystkich takich nazw typów. Aby obejść ten problem, nazwa typu i wszystkie użycia muszą zostać zaznaczone za pomocą znacznika @
.
class required {} // Error CS9029
class @required {} // No error
Zostało to zrobione, ponieważ required
jest teraz modyfikatorem składowym dla właściwości i pól.
Więcej informacji na temat tej zmiany można znaleźć w skojarzonym zgłoszeniu csharplang.
Roslyn breaking changes