Členové instance jen pro čtení
Poznámka
Tento článek je specifikace funkce. Specifikace slouží jako návrhový dokument pro funkci. Zahrnuje navrhované změny specifikace spolu s informacemi potřebnými při návrhu a vývoji funkce. Tyto články se publikují, dokud nebudou navrhované změny specifikace finalizovány a začleněny do aktuální specifikace ECMA.
Mezi specifikací funkce a dokončenou implementací může docházet k nějakým nesrovnalostem. Tyto rozdíly jsou zaznamenány v poznámkách ze schůzky návrhu jazyka (LDM) .
Další informace o procesu přijetí specifikací funkcí do jazyka C# najdete v článku o specifikacích .
Problém šampiona: <https://github.com/dotnet/csharplang/issues/1710>
Shrnutí
Umožněte možnost určit jednotlivé členy instance ve struktuře, které neupravují stav, podobně jako readonly struct
specifikuje, že žádné členy instance nemění stav.
Stojí za zmínku, že člen instance jen pro čtení != čistý člen instance.
čistý člen instance zaručuje, že žádný stav nebude změněn. Člen instance readonly
zaručuje, že stav instance nebude změněn.
Všechny členy instance na readonly struct
lze považovat implicitně členy instance jen pro čtení explicitní členy instance jen pro čtení deklarované u struktur bez čtení by se chovaly stejným způsobem. Pokud byste například volali člena instance (na aktuální instanci nebo na poli této instance), který sám nebyl pouze pro čtení, stále by vytvořili skryté kopie.
Motivace
Před C# 8.0 mají uživatelé možnost vytvářet readonly struct
typy, které kompilátor vynucuje, aby všechna pole byla jen pro čtení (a podle rozšíření, že žádný člen instance nemění stav). Existují však některé scénáře, kdy máte existující rozhraní API, které zveřejňuje pole nebo má kombinaci členů, které se mění i nemění. Za těchto okolností nemůžete typ označit jako readonly
(jedná se o zásadní změnu).
To obvykle nemá velký dopad, s výjimkou případů in
parametrů. U in
parametrů pro nečtené struktury kompilátor vytvoří kopii parametru pro vyvolání každého člena instance, protože nemůže zaručit, že vyvolání neupraví vnitřní stav. To může vést k mnoha kopiím a horšímu celkovému výkonu, než kdybyste právě předali strukturu přímo jako hodnotu. Příklad najdete v ukázkovém kódu na sharplab
Mezi další scénáře, kdy mohou dojít ke skrytým kopiím, patří pole static readonly
a literální hodnoty . Pokud budou v budoucnu podporovány, blittable konstanty se ocitnou ve stejné situaci; to znamená, že v současnosti všechny vyžadují úplnou kopii (při volání členské funkce), pokud struktura není označena readonly
.
Návrh
Umožňuje uživateli určit, že člen instance je sám o sobě, readonly
a neupravuje stav instance (s veškerým odpovídajícím ověřením provedeným kompilátorem samozřejmě). Například:
public struct Vector2
{
public float x;
public float y;
public readonly float GetLengthReadonly()
{
return MathF.Sqrt(LengthSquared);
}
public float GetLength()
{
return MathF.Sqrt(LengthSquared);
}
public readonly float GetLengthIllegal()
{
var tmp = MathF.Sqrt(LengthSquared);
x = tmp; // Compiler error, cannot write x
y = tmp; // Compiler error, cannot write y
return tmp;
}
public readonly float LengthSquared
{
get
{
return (x * x) +
(y * y);
}
}
}
public static class MyClass
{
public static float ExistingBehavior(in Vector2 vector)
{
// This code causes a hidden copy, the compiler effectively emits:
// var tmpVector = vector;
// return tmpVector.GetLength();
//
// This is done because the compiler doesn't know that `GetLength()`
// won't mutate `vector`.
return vector.GetLength();
}
public static float ReadonlyBehavior(in Vector2 vector)
{
// This code is emitted exactly as listed. There are no hidden
// copies as the `readonly` modifier indicates that the method
// won't mutate `vector`.
return vector.GetLengthReadonly();
}
}
Pro přístupové metody vlastností lze použít pouze pro čtení, což naznačuje, že this
nebude modifikováno v přístupové metodě. Následující příklady mají settery pouze pro čtení, protože tyto přístupové metody upravují stav členského pole, ale neupravují hodnotu tohoto členského pole.
public readonly int Prop1
{
get
{
return this._store["Prop1"];
}
set
{
this._store["Prop1"] = value;
}
}
Při použití readonly
na syntaxi vlastnosti to znamená, že všechny přístupové objekty jsou readonly
.
public readonly int Prop2
{
get
{
return this._store["Prop2"];
}
set
{
this._store["Prop2"] = value;
}
}
Režim jen pro čtení lze použít pouze pro příslušnosti, které nemění jejich obsahující typ.
public int Prop3
{
readonly get
{
return this._prop3;
}
set
{
this._prop3 = value;
}
}
Na některé automaticky implementované vlastnosti lze použít jen pro čtení, ale nebude mít smysluplný účinek. Kompilátor bude zacházet se všemi automaticky implementovanými gettery jako s jen pro čtení, ať už je klíčové slovo readonly
přítomno, nebo ne.
// Allowed
public readonly int Prop4 { get; }
public int Prop5 { readonly get; set; }
// Not allowed
public int Prop6 { readonly get; }
public readonly int Prop7 { get; set; }
public int Prop8 { get; readonly set; }
Vlastnost 'readonly' lze aplikovat na ručně implementované události, ale ne na události podobné polím. U jednotlivých přístuporů událostí (přidat/odebrat) nelze použít vlastnost jen pro čtení.
// Allowed
public readonly event Action<EventArgs> Event1
{
add { }
remove { }
}
// Not allowed
public readonly event Action<EventArgs> Event2;
public event Action<EventArgs> Event3
{
readonly add { }
readonly remove { }
}
public static readonly event Event4
{
add { }
remove { }
}
Další příklady syntaxe:
- Členové s výrazovým tělem:
public readonly float ExpressionBodiedMember => (x * x) + (y * y);
- Obecná omezení:
public readonly void GenericMethod<T>(T value) where T : struct { }
Kompilátor by vygeneroval člena instance jako obvykle a navíc vygeneroval rozpoznaný atribut kompilátoru označující, že člen instance neupravuje stav. Díky tomu se skrytý parametr this
místo in T
stane ref T
.
To by uživateli umožnilo bezpečně volat metodu instance bez nutnosti kompilátoru vytvořit kopii.
Tato omezení by zahrnovala:
- Modifikátor
readonly
nelze použít u statických metod, konstruktorů nebo destruktorů. - Modifikátor
readonly
nelze použít u delegátů. - Modifikátor
readonly
nelze použít u členů třídy nebo rozhraní.
Nevýhody
Stejné nevýhody jako existují u readonly struct
metod dnes. Určitý kód může stále způsobit skryté kopie.
Poznámky
Použití atributu nebo jiného klíčového slova může být také možné.
Tento návrh souvisí s (ale spíše jako podmnožina) functional purity
a/nebo constant expressions
, na které již existují některé návrhy.
C# feature specifications