Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Not
Bu makale bir özellik belirtimidir. Belirtim, özelliğin tasarım belgesi olarak görev alır. Önerilen belirtim değişikliklerini ve özelliğin tasarımı ve geliştirilmesi sırasında gereken bilgileri içerir. Bu makaleler, önerilen belirtim değişiklikleri son haline getirilene ve geçerli ECMA belirtimine dahil edilene kadar yayımlanır.
Özellik belirtimi ile tamamlanan uygulama arasında bazı tutarsızlıklar olabilir. Bu farklılıklar, ilgili dil tasarım toplantısı (LDM) notlarındakaydedilir.
Özellik belirtimlerini C# dil standardına benimseme işlemi hakkında daha fazla bilgi edinmek için belirtimleri makalesinde bulabilirsiniz.
Şampiyon sorunu: https://github.com/dotnet/csharplang/issues/4934
Özet
Önerilen değişiklikler:
- Öznitelikleri olan lambdalara izin ver
- Açık dönüş türüne sahip lambdalara izin ver
- Lambda ve metot grupları için doğal bir temsilci türü türet
Motivasyon
Lambda'lardaki öznitelikler için destek, metotlar ve yerel işlevlerle eşitlik sağlar.
Açık dönüş türleri desteği, açık türlerin belirtilebileceği lambda parametreleriyle simetri sağlar. Açık dönüş türlerine izin vermek, aşırı yükleme çözümlemesinin imzayı belirlemek için şu anda lambda gövdesini bağlaması gereken iç içe lambdalarda, derleyici performansı üzerinde daha iyi bir kontrol imkanı da sağlar.
Lambda ifadeleri ve yöntem grupları için doğal bir tür, var bildirimlerinde başlatıcılar olarak dahil olmak üzere açık bir temsilci türü olmadan lambdaların ve yöntem gruplarının kullanılabildiği daha fazla senaryoya olanak sağlar.
Lambdalar ve yöntem grupları için açık temsilci türlerinin zorunlu olması müşteriler için bir sürtüşme noktası olmuştur ve MapActionüzerinde yapılan son çalışmalarla ASP.NET ilerlemesi engel haline gelmiştir.
ASP.NET MapAction önerilen değişiklikler olmadan (MapAction() bir System.Delegate bağımsız değişken alır):
[HttpGet("/")] Todo GetTodo() => new(Id: 0, Name: "Name");
app.MapAction((Func<Todo>)GetTodo);
[HttpPost("/")] Todo PostTodo([FromBody] Todo todo) => todo;
app.MapAction((Func<Todo, Todo>)PostTodo);
ASP.NET MapAction, yöntem grupları için doğal türler ile.
[HttpGet("/")] Todo GetTodo() => new(Id: 0, Name: "Name");
app.MapAction(GetTodo);
[HttpPost("/")] Todo PostTodo([FromBody] Todo todo) => todo;
app.MapAction(PostTodo);
ASP.NET MapAction, lambda ifadeleri için öznitelikler ve doğal türler ile birlikte:
app.MapAction([HttpGet("/")] () => new Todo(Id: 0, Name: "Name"));
app.MapAction([HttpPost("/")] ([FromBody] Todo todo) => todo);
Öznitelik
Lambda ifadelerine ve lambda parametrelerine öznitelikler eklenebilir. Yöntem öznitelikleri ile parametre öznitelikleri arasındaki belirsizliği önlemek için öznitelikleri olan bir lambda ifadesinin parantez içinde parametre listesi kullanması gerekir. Parametre türleri gerekli değildir.
f = [A] () => { }; // [A] lambda
f = [return:A] x => x; // syntax error at '=>'
f = [return:A] (x) => x; // [A] lambda
f = [A] static x => x; // syntax error at '=>'
f = ([A] x) => x; // [A] x
f = ([A] ref int x) => x; // [A] x
Aynı öznitelik listesinde virgülle ayrılmış veya ayrı öznitelik listeleri olarak birden çok öznitelik belirtilebilir.
var f = [A1, A2][A3] () => { }; // ok
var g = ([A1][A2, A3] int x) => x; // ok
Öznitelikler, söz dizimi ile bildirilen delegate { } yöntemler için desteklenmez.
f = [A] delegate { return 1; }; // syntax error at 'delegate'
f = delegate ([A] int x) { return x; }; // syntax error at '['
Ayrıştırıcı, öğe ataması olan bir koleksiyon başlatıcısını lambda ifadesiyle bir koleksiyon başlatıcısından ayırt etmek için ileriye bakar.
var y = new C { [A] = x }; // ok: y[A] = x
var z = new C { [A] x => x }; // ok: z[0] = [A] x => x
Ayrıştırıcı, ?[ koşullu öğe erişiminin başlangıcı olarak ele alır.
x = b ? [A]; // ok
y = b ? [A] () => { } : z; // syntax error at '('
Lambda ifadesi veya lambda parametrelerindeki öznitelikler, lambda'ya karşılık gelen yöntemdeki meta verilere aktarılır.
Genel olarak, müşteriler lambda ifadelerinin ve yerel işlevlerin kaynaktan meta veriye nasıl eşlenmesine bağlı olmamalıdır. Derleyici sürümleri arasında lambda ve yerel işlevlerin yayılma şekli değişebilir ve değişmiştir.
Burada önerilen değişiklikler Delegate temelli senaryoya hedeflenmiştir.
Bir MethodInfo örneğiyle ilişkili olan Delegate'ı incelemek, lambda ifadesinin veya yerel işlevin imzasını belirlemek için, varsa açık öznitelikler ve derleyici tarafından eklenen varsayılan parametreler gibi ek meta veriler de dahil olmak üzere, geçerli olmalıdır.
Bu, ASP.NET gibi ekiplerin lambdalar ve yerel işlevler için sıradan yöntemlerle aynı davranışları sunmasını sağlar.
Açık dönüş türü
Parantez içinde parametre listesinden önce açık bir dönüş türü belirtilebilir.
f = T () => default; // ok
f = short x => 1; // syntax error at '=>'
f = ref int (ref int x) => ref x; // ok
f = static void (_) => { }; // ok
f = async async (async async) => async; // ok?
Ayrıştırıcı, bir yöntem çağrısını T() bir lambda ifadesinden T () => eayırt etmek için ileri doğru bakar.
delegate { } söz dizimi ile bildirilen anonim yöntemler için açık dönüş türleri desteklenmez.
f = delegate int { return 1; }; // syntax error
f = delegate int (int x) { return x; }; // syntax error
Yöntem türü çıkarımı, açık bir lambda dönüş türünden tam bir çıkarım yapmalıdır.
static void F<T>(Func<T, T> f) { ... }
F(int (i) => i); // Func<int, int>
Lambda dönüş türünden temsilci dönüş türüne (parametre türleri için benzer davranışla eşleşen) varyans dönüştürmelerine izin verilmez.
Func<object> f1 = string () => null; // error
Func<object?> f2 = object () => x; // warning
Ayrıştırıcı, ifadeler içinde ek parantezler olmadan ref dönüş türlerine sahip lambda ifadelerine izin verir.
d = ref int () => x; // d = (ref int () => x)
F(ref int () => x); // F((ref int () => x))
var, lambda ifadeleri için açık bir dönüş türü olarak kullanılamaz.
class var { }
d = var (var v) => v; // error: contextual keyword 'var' cannot be used as explicit lambda return type
d = @var (var v) => v; // ok
d = ref var (ref var v) => ref v; // error: contextual keyword 'var' cannot be used as explicit lambda return type
d = ref @var (ref var v) => ref v; // ok
Doğal (işlev) türü
anonim işlev ifadesi (§12.19) ( lambda ifadesi veya anonim yöntem) parametre türleri açıksa ve dönüş türü açıksa veya çıkarılabiliyorsa doğal bir türe sahiptir (bkz. §12.6.3.13).
Yöntem grubundaki tüm aday yöntemlerin ortak bir imzası varsa, yöntem grubu doğal bir türe sahiptir. (Yöntem grubu uzantı yöntemlerini içerebilirse, adaylar kapsayan türü ve tüm uzantı yöntemi kapsamlarını içerir.)
Anonim işlev ifadesinin veya yöntem grubunun doğal türü function_type. function_type bir yöntem imzasını temsil eder: parametre türleri ve başvuru türleri ve dönüş türü ve başvuru türü. Aynı imzaya sahip anonim işlev ifadeleri veya yöntem grupları aynı function_typesahiptir.
Function_types yalnızca birkaç belirli bağlamda kullanılır:
- örtük ve açık dönüştürmeler
- yöntem türü çıkarımı (§12.6.3) ve en iyi ortak tür (§12.6.3.15)
-
varbaşlatıcıları
Yalnızca derleme zamanında bir function_type vardır: function_types kaynakta veya meta verilerde görünmez.
Dönüşüm
function_typeF biriminden function_type dönüştürme işlemleri örtük olarak vardır.
- Parametreler ve dönüş türleri 'ün,
G'ün parametreleri ve dönüş türüne değişken olarak dönüştürülebilir olduğu durumda,FGolur. -
System.MulticastDelegateveyaSystem.MulticastDelegate'in temel sınıfları ya da arabirimleri -
System.Linq.Expressions.ExpressionveyaSystem.Linq.Expressions.LambdaExpression
Anonim işlev ifadeleri ve yöntem grupları, zaten ifade 'den temsilci türlerine ve ifad ağacı türlerine dönüşümlere sahiptir (bkz. anonim işlev dönüşümleri §10.7 ve yöntem grubu dönüşümleri §10.8). Bu dönüştürmeler, kesin olarak belirlenmiş temsilci türlerine ve ifade ağacı türlerine dönüştürmek için yeterlidir. Yukarıdaki function_type dönüştürmeleri, yalnızca tür 'ten temel türlere dönüştürmeleri ekler: System.MulticastDelegate, System.Linq.Expressions.Expressionvb.
Bir türden function_type'ye, function_typedışında bir dönüştürme yoktur. Kaynakta function_types başvurulamadığından, function_types için açık bir dönüştürme yoktur.
System.MulticastDelegate veya temel türe veya arabirime dönüştürme, anonim işlevi veya yöntem grubunu uygun bir temsilci türünün örneği olarak gerçekleştirir.
System.Linq.Expressions.Expression<TDelegate> veya temel türe dönüştürme, lambda ifadesini uygun bir temsilci türüne sahip bir ifade ağacı olarak gerçekleştirir.
Delegate d = delegate (object obj) { }; // Action<object>
Expression e = () => ""; // Expression<Func<string>>
object o = "".Clone; // Func<object>
Function_type dönüştürmeleri , §10.4 örtük veya açık standart dönüştürmeler değildir ve kullanıcı tanımlı dönüştürme işlecinin anonim bir işlev veya yöntem grubu için geçerli olup olmadığı belirlenirken dikkate alınmaz. Kullanıcı tanımlı dönüştürmelerin değerlendirilmesinden §10.5.3:
Dönüştürme işlecinin uygulanabilir olması için, kaynak türünden işlecin işlenen türüne standart dönüştürme (§10,4) gerçekleştirilmesi ve işlecin sonuç türünden hedef türüne standart bir dönüştürme gerçekleştirilmesi mümkün olmalıdır.
class C
{
public static implicit operator C(Delegate d) { ... }
}
C c;
c = () => 1; // error: cannot convert lambda expression to type 'C'
c = (C)(() => 2); // error: cannot convert lambda expression to type 'C'
Bir metod grubu, object'a örtük olarak dönüştürüldüğü için bir uyarı bildirilir; bu, dönüştürmenin geçerli ancak belki de istem dışı olduğuna işaret eder.
Random r = new Random();
object obj;
obj = r.NextDouble; // warning: Converting method group to 'object'. Did you intend to invoke the method?
obj = (object)r.NextDouble; // ok
Tür çıkarımı
Tür çıkarımı için mevcut kurallar çoğunlukla değişmemiştir (bkz. §12.6.3). Ancak, aşağıda tür çıkarımının belirli aşamalarında birkaç değişiklik vardır.
İlk aşama
İlk aşama (§12.6.3.2), anonim bir işlevin, Ti bir temsilci veya ifade ağacı türü olmasa bile (örneğin Ti kısıtlanmış bir tür parametresi) System.Delegate'ye bağlanmasına olanak tanır.
yöntem bağımsız değişkenlerinin her biri için
Ei:
Eianonim bir işlev veTibir temsilci türü veya ifade ağacı türüyse, 'denEi'aTive 'denEi'eTiyapılır.- Aksi takdirde,
Eibir türUvarsa vexibir değer parametresiyse, 'denU'eTiyapılır.- Aksi takdirde,
Eibir türU'e sahipse vexirefveyaoutbir parametreyse,Tiyapılır.- Aksi takdirde, bu bağımsız değişkene dair bir çıkarımda bulunulmaz.
Açık dönüş türü çıkarımı
Bir açık dönüş türü çıkarımı, bir tür aşağıdaki şekildeiçin bir ifade
ETyapılır:
E,Uraçık dönüş türüne sahip anonim bir işlevse veTdönüş türüVrolan bir temsilci türü veya ifade ağacı türüyse, tam bir çıkarım (§12.6.3.9) ,Ur'denVr'e yapılır.
Düzeltme
Düzeltme (§12.6.3.12) diğer dönüştürmelerin function_type dönüştürmeler yerine tercih edilmesini sağlar. (Lambda ifadeleri ve yöntem grubu ifadeleri yalnızca alt sınırlara katkıda bulunur, bu nedenle yalnızca alt sınırlar için function_types işlenmesi gerekir.)
Sınır kümesine sahip
Xitürü değişkeni aşağıdaki gibi sabit :
Ujaday türleri kümesi,işlev türü olmayan herhangi bir tür varsa, işlev türlerinin alt sınırlarda yoksayıldığıXiiçin sınır kümesindeki tüm türlerin kümesi olarak başlar.- Ardından her
Xi'ı teker teker inceleyeceğiz: HerU'nin kesin sınırıXiiçin,Ujile aynı olmayan tümUtürleri aday kümesinden kaldırılır.Uher alt sınırXiiçin,Ujörtük dönüştürme olmayanUtüm türler aday kümesinden kaldırılır.Uher üst sınırXiiçin,Ujörtük dönüştürme olmayan tüm türlerUaday kümesinden kaldırılır.- Kalan aday türleri arasında
Ujdiğer tüm aday türlerine örtük dönüştürmenin olduğu benzersiz bir türVvarsa,XiVolarak sabitlenmiştir.- Aksi takdirde tür çıkarımı başarısız olur.
En iyi yaygın tür
En iyi ortak tür (§12.6.3.15) tür çıkarımı açısından tanımlanır, dolayısıyla yukarıdaki tür çıkarımı değişiklikleri en iyi ortak tür için de geçerlidir.
var fs = new[] { (string s) => s.Length, (string s) => int.Parse(s) }; // Func<string, int>[]
var
İşlev türlerine sahip anonim işlevler ve yöntem grupları, var bildirimlerinde başlatıcı olarak kullanılabilir.
var f1 = () => default; // error: cannot infer type
var f2 = x => x; // error: cannot infer type
var f3 = () => 1; // System.Func<int>
var f4 = string () => null; // System.Func<string>
var f5 = delegate (object o) { }; // System.Action<object>
static void F1() { }
static void F1<T>(this T t) { }
static void F2(this string s) { }
var f6 = F1; // error: multiple methods
var f7 = "".F1; // error: the delegate type could not be inferred
var f8 = F2; // System.Action<string>
İşlev türleri, yok saymalarda atamalarda kullanılmaz.
d = () => 0; // ok
_ = () => 1; // error
Temsilci türleri
Parametre türleri P1, ..., Pn ve dönüş türü R olan anonim işlev veya yöntem grubu için temsilci türü:
- herhangi bir parametre veya dönüş değeri değere göre değilse ya da 16'dan fazla parametre varsa ya da parametre türlerinden veya dönüşlerinden herhangi biri geçerli tür bağımsız değişkenleri değilse (örneğin,
(int* p) => { }), temsilci anonim işlev veya yöntem grubuyla eşleşen imzalı, parametre adlarıinternalveya tek bir parametreysearg1, ..., argnolan birleştirilmişarganonim temsilci türüdür; -
Rvoidise, temsilci türüSystem.Action<P1, ..., Pn>olur; - aksi takdirde temsilci türü
System.Func<P1, ..., Pn, R>.
Derleyici, gelecekte System.Action<> ve System.Func<> türlerine daha fazla imza bağlanmasına izin verebilir (örneğin, ref struct türleri bağımsız değişken olarak kabul ediliyorsa).
Yöntem grubu imzasındaki modopt() veya modreq(), karşılık gelen temsilci türünde göz ardı edilir.
Aynı derlemedeki iki anonim işlev veya yöntem grubu aynı parametre türlerine ve değiştiricilere ve aynı dönüş türüne ve değiştiricilere sahip sentezlenmiş temsilci türleri gerektiriyorsa, derleyici aynı sentezlenmiş temsilci türünü kullanır.
Aşırı yükleme çözümü
Daha iyi fonksiyon üyesi (§12.6.4.3), dönüştürmelerin ve lambda ifadelerinden veya yöntem gruplarından çıkarılan tür bağımsız değişkenlerinin hiçbirinin yer almadığı üyeleri tercih edecek şekilde güncellendi.
Daha iyi işlev üyesi
... Bağımsız değişken listesi
A, bir dizi bağımsız değişken ifadesi{E1, E2, ..., En}ve parametre türleriMpveMqolan iki geçerli işlev üyesi{P1, P2, ..., Pn}ve{Q1, Q2, ..., Qn}ile verildiğinde,Mp'nın daha iyi bir işlev üyesi olduğu,Mq'e göre tanımlanır.
- Her bağımsız değişken için ,
Ex'denPx'ye örtük bir dönüştürme, bir işlev türü dönüşümüdeğildir ve
Mpgenel olmayan bir yöntemdir veyaMptür parametreleri{X1, X2, ..., Xp}ve tür bağımsız değişkeni bir ifadeden veyaXidışında bir türden çıkarılır her tür parametresi için genel bir yöntemdir ve- En az bir bağımsız değişken için
Yitür parametreleri ve en az bir tür parametresi için genel bir yöntemdir- her bağımsız değişken için,
Ex'denQx'ye örtük dönüştürme,Ex'denPx'a örtük dönüştürmeden daha iyi değildir ve en az bir bağımsız değişken içinEx'denPxdönüştürme,Ex'denQx'e dönüştürmeden daha iyidir.
§12.6.4.5numaralı ifade için daha iyi bir dönüştürme, lambda ifadeleri veya yöntem gruplarından çıkarılan türleri içermeyen dönüştürmelerin tercih edilmesi yönünde güncellenmiştir.
İfadedeki dönüşümü iyileştirme
C1bir ifadedenEtürüne dönüştüren örtük dönüştürmeT1ve bir ifadedenC2türEtürüne dönüştüren örtük dönüştürmeT2göz önünde bulundurulduğunda,C1daha iyiC2:
C1bir fonksiyon_türü_dönüştürme değil veC2bir fonksiyon_türü_dönüştürmeveyaEsabit olmayan bir ara_değişken_dizi_ifadesi'dir,C1bir örtük_dizi_dönüştürücüsü'dir,T1bir uygulanabilir_ara_değişken_dizi_tipi'dir veC2bir örtük_dizi_dönüştürücüsüdeğildir ya daET2tam olarak eşleşmez ve aşağıdakilerden en az biri geçerlidir:
Sözdizimi
lambda_expression
: modifier* identifier '=>' (block | expression)
| attribute_list* modifier* type? lambda_parameters '=>' (block | expression)
;
lambda_parameters
: lambda_parameter
| '(' (lambda_parameter (',' lambda_parameter)*)? ')'
;
lambda_parameter
: identifier
| attribute_list* modifier* type? identifier equals_value_clause?
;
Açık sorunlar
Tamlık için lambda ifade parametreleri için varsayılan değerler desteklenmeli mi?
Lambda ifadelerinde System.Diagnostics.ConditionalAttribute'in kullanılmasına, lambda ifadesinin koşullu olarak kullanılabileceği birkaç durum bulunduğundan izin verilmemeli mi?
([Conditional("DEBUG")] static (x, y) => Assert(x == y))(a, b); // ok?
function_type, sonuçta elde edilen temsilci türüne ek olarak derleyici API'sinden kullanılabilir mi?
Şu anda, çıkarım yapılan temsilci türü, parametre ve dönüş türleri geçerli tür bağımsız değişkenleri System.Action<> olduğunda ve 16'dan fazla parametre olmadığında System.Func<> veya kullanır. Beklenen Action<> veya Func<> türü eksikse, hata bildirilir. Bunun yerine, derleyici arity göz önünde bulundurmaksızın System.Action<> mu yoksa System.Func<> mi kullanmalıdır? Beklenen tür eksikse, bir temsilci türünü sentezle aksi takdirde?
C# feature specifications