İşlev IşaretçileriFunction Pointers
ÖzetSummary
Bu teklif, günümüzde C# ' de şu anda etkin şekilde erişilemeyen Il işlem kodları 'ları kullanan dil yapıları sağlar: ldftn ve calli .This proposal provides language constructs that expose IL opcodes that cannot currently be accessed efficiently, or at all, in C# today: ldftn and calli. Bu Il Opcode 'ları yüksek performans kodunda önemli olabilir ve geliştiricilerin bunlara erişmek için etkili bir yol olması gerekir.These IL opcodes can be important in high performance code and developers need an efficient way to access them.
MotivasyonMotivation
Bu özelliğin ilgi çekici ve arka planı, aşağıdaki konuda açıklanmaktadır (özelliğin olası bir uygulamasıdır):The motivations and background for this feature are described in the following issue (as is a potential implementation of the feature):
https://github.com/dotnet/csharplang/issues/191
Bu, derleyici iç bilgileri için alternatif bir tasarım teklifinde bulunurThis is an alternate design proposal to compiler intrinsics
Ayrıntılı tasarımDetailed Design
İşlev işaretçileriFunction pointers
Dil, sözdizimini kullanarak işlev işaretçilerinin bildirimine izin verir delegate* .The language will allow for the declaration of function pointers using the delegate* syntax. Tam söz dizimi, sonraki bölümde ayrıntılı olarak açıklanmıştır, ancak tarafından kullanılan sözdizimine Func ve tür bildirimlerine benzemesi amaçlanmıştır Action .The full syntax is described in detail in the next section but it is meant to resemble the syntax used by Func and Action type declarations.
unsafe class Example {
void Example(Action<int> a, delegate*<int, void> f) {
a(42);
f(42);
}
}
Bu türler, ECMA-335 ' de özetlenen işlev işaretçisi türü kullanılarak temsil edilir.These types are represented using the function pointer type as outlined in ECMA-335. Bu, bir öğesinin çağrılması delegate* calli delegate callvirt yönteminin yöntemi üzerinde kullanacağı yerde kullanacağı anlamına gelir Invoke .This means invocation of a delegate* will use calli where invocation of a delegate will use callvirt on the Invoke method.
Sözdizimi, her iki yapı için de özdeş.Syntactically though invocation is identical for both constructs.
Yöntem işaretçilerinin ECMA-335 tanımı, tür imzasının bir parçası olarak çağırma kuralını içerir (Bölüm 7,1).The ECMA-335 definition of method pointers includes the calling convention as part of the type signature (section 7.1).
Varsayılan çağırma kuralı olacaktır managed .The default calling convention will be managed. Yönetilmeyen çağırma kuralları, unmanaged delegate* çalışma zamanı platform varsayılanını kullanacak şekilde sözdizimi eklenerek bir anahtar sözcük eklenerek belirtilebilir.Unmanaged calling conventions can by specified by putting an unmanaged keyword afer the delegate* syntax, which will use the runtime platform default. Belirli yönetilmeyen kurallar, unmanaged ad alanında ile başlayan herhangi bir tür belirtilerek CallConv System.Runtime.CompilerServices , ön eke ayrılmadan anahtar sözcüğe parantez içinde belirtilebilir CallConv .Specific unmanaged conventions can then be specified in brackets to the unmanaged keyword by specifying any type starting with CallConv in the System.Runtime.CompilerServices namespace, leaving off the CallConv prefix. Bu türler programın çekirdek kitaplığından gelmelidir ve geçerli birleşimler kümesi platforma bağımlıdır.These types must come from the program's core library, and the set of valid combinations is platform-dependent.
//This method has a managed calling convention. This is the same as leaving the managed keyword off.
delegate* managed<int, int>;
// This method will be invoked using whatever the default unmanaged calling convention on the runtime
// platform is. This is platform and architecture dependent and is determined by the CLR at runtime.
delegate* unmanaged<int, int>;
// This method will be invoked using the cdecl calling convention
// Cdecl maps to System.Runtime.CompilerServices.CallConvCdecl
delegate* unmanaged[Cdecl] <int, int>;
// This method will be invoked using the stdcall calling convention, and suppresses GC transition
// Stdcall maps to System.Runtime.CompilerServices.CallConvStdcall
// SuppressGCTransition maps to System.Runtime.CompilerServices.CallConvSuppressGCTransition
delegate* unmanaged[Stdcall, SuppressGCTransition] <int, int>;
Türler arasındaki dönüştürmeler, delegate* çağırma kuralı dahil olmak üzere imzasına göre yapılır.Conversions between delegate* types is done based on their signature including the calling convention.
unsafe class Example {
void Conversions() {
delegate*<int, int, int> p1 = ...;
delegate* managed<int, int, int> p2 = ...;
delegate* unmanaged<int, int, int> p3 = ...;
p1 = p2; // okay p1 and p2 have compatible signatures
Console.WriteLine(p2 == p1); // True
p2 = p3; // error: calling conventions are incompatible
}
}
delegate*Tür, standart bir işaretçi türünün tüm özelliklerine ve kısıtlamalarına sahip olduğu anlamına gelen bir işaretçi türüdür:A delegate* type is a pointer type which means it has all of the capabilities and restrictions of a standard pointer type:
- Yalnızca bir bağlamda geçerlidir
unsafe.Only valid in anunsafecontext. - Bir
delegate*parametre veya dönüş türü içeren yöntemler yalnızca birunsafeiçerikten çağrılabilir.Methods which contain adelegate*parameter or return type can only be called from anunsafecontext. - Öğesine dönüştürülemez
object.Cannot be converted toobject. - Genel bağımsız değişken olarak kullanılamaz.Cannot be used as a generic argument.
- Örtük olarak
delegate*öğesine dönüştürülebilirvoid*.Can implicitly convertdelegate*tovoid*. - , ' Dan öğesine açıkça dönüştürülebilir
void*delegate*.Can explicitly convert fromvoid*todelegate*.
LarındanRestrictions:
- Özel öznitelikler bir
delegate*veya öğelerinden hiçbirine uygulanamaz.Custom attributes cannot be applied to adelegate*or any of its elements. - Bir
delegate*parametre şu şekilde işaretlenemezparamsAdelegate*parameter cannot be marked asparams - Bir
delegate*tür, normal bir işaretçi türünün tüm kısıtlamalarına sahiptir.Adelegate*type has all of the restrictions of a normal pointer type. - İşaretçi aritmetiği doğrudan işlev işaretçisi türlerinde gerçekleştirilemez.Pointer arithmetic cannot be performed directly on function pointer types.
İşlev işaretçisi sözdizimiFunction pointer syntax
Tam işlev işaretçisi sözdizimi aşağıdaki dilbilgisinde temsil edilir:The full function pointer syntax is represented by the following grammar:
pointer_type
: ...
| funcptr_type
;
funcptr_type
: 'delegate' '*' calling_convention_specifier? '<' funcptr_parameter_list funcptr_return_type '>'
;
calling_convention_specifier
: 'managed'
| 'unmanaged' ('[' unmanaged_calling_convention ']')?
;
unmanaged_calling_convention
: 'Cdecl'
| 'Stdcall'
| 'Thiscall'
| 'Fastcall'
| identifier (',' identifier)*
;
funptr_parameter_list
: (funcptr_parameter ',')*
;
funcptr_parameter
: funcptr_parameter_modifier? type
;
funcptr_return_type
: funcptr_return_modifier? return_type
;
funcptr_parameter_modifier
: 'ref'
| 'out'
| 'in'
;
funcptr_return_modifier
: 'ref'
| 'ref readonly'
;
Hayır calling_convention_specifier sağlanmazsa, varsayılan olur managed .If no calling_convention_specifier is provided, the default is managed. ' Nin kesin meta veri kodlaması calling_convention_specifier ve identifier içinde geçerli olduğu, unmanaged_calling_convention çağırma kurallarının meta veri gösterimininkapsamına alınmıştır.The precise metadata encoding of the calling_convention_specifier and what identifiers are valid in the unmanaged_calling_convention is covered in Metadata Representation of Calling Conventions.
delegate int Func1(string s);
delegate Func1 Func2(Func1 f);
// Function pointer equivalent without calling convention
delegate*<string, int>;
delegate*<delegate*<string, int>, delegate*<string, int>>;
// Function pointer equivalent with calling convention
delegate* managed<string, int>;
delegate*<delegate* managed<string, int>, delegate*<string, int>>;
İşlev işaretçisi dönüştürmeleriFunction pointer conversions
Güvenli olmayan bir bağlamda, kullanılabilir örtük dönüştürmeler (örtük dönüştürmeler) kümesi aşağıdaki örtük işaretçi dönüşümlerini içerecek şekilde genişletilir:In an unsafe context, the set of available implicit conversions (Implicit conversions) is extended to include the following implicit pointer conversions:
- Mevcut dönüşümlerExisting conversions
- Funcptr _ türünden
F0başka bir funcptr _ türüneF1, aşağıdakilerin tümü doğru olarak sağlandıysa:From funcptr_typeF0to another funcptr_typeF1, provided all of the following are true:F0``F1aynı sayıda parametreye sahiptir ve içindeki her bir parametreD0nF0refoutiniçindeki karşılık gelen parametresiyle aynı, veya değiştiricilere sahiptirD1nF1.F0andF1have the same number of parameters, and each parameterD0ninF0has the sameref,out, orinmodifiers as the corresponding parameterD1ninF1.- Her bir değer parametresi (Hayır
ref, veya değiştirici içeren bir parametreout) içinin, bir kimlik dönüştürme, örtük başvuru dönüştürme veya içindeki parametre türünden ' de karşılık gelen parametre türüne sahip örtülü işaretçi dönüştürme bulunurF0F1.For each value parameter (a parameter with noref,out, orinmodifier), an identity conversion, implicit reference conversion, or implicit pointer conversion exists from the parameter type inF0to the corresponding parameter type inF1. - Her
ref,outveya parametresi içininiçindeki parametre türü,F0içindeki karşılık gelen parametre türüyle aynıdırF1.For eachref,out, orinparameter, the parameter type inF0is the same as the corresponding parameter type inF1. - Dönüş türü değer (Hayır
refveyaref readonly) ise, bir kimlik, örtük başvuru veya dönüş türünden dönüş türüne örtülü bir işaretçi dönüştürmesi vardırF1F0.If the return type is by value (noreforref readonly), an identity, implicit reference, or implicit pointer conversion exists from the return type ofF1to the return type ofF0. - Dönüş türü başvuruya (veya) göre ise
refref readonly, dönüş türü verefdeğiştiriciler,F1dönüş türü verefdeğiştiricilerine benzerF0.If the return type is by reference (reforref readonly), the return type andrefmodifiers ofF1are the same as the return type andrefmodifiers ofF0. - Çağırma kuralı,
F0çağırma kuralıyla aynıdırF1.The calling convention ofF0is the same as the calling convention ofF1.
Hedef yöntemlere yönelik adrese izin verAllow address-of to target methods
Yöntem gruplarına artık bir adres ifadesi için bağımsız değişken olarak izin verilir.Method groups will now be allowed as arguments to an address-of expression. Böyle bir ifadenin türü, delegate* hedef yöntemin ve yönetilen bir çağrı kuralının denk imzasına sahip olan bir ifade olacaktır:The type of such an expression will be a delegate* which has the equivalent signature of the target method and a managed calling convention:
unsafe class Util {
public static void Log() { }
void Use() {
delegate*<void> ptr1 = &Util.Log;
// Error: type "delegate*<void>" not compatible with "delegate*<int>";
delegate*<int> ptr2 = &Util.Log;
}
}
Güvenli olmayan bir bağlamda, aşağıdakilerin tümü doğru ise bir yöntem bir M işlev işaretçisi türüyle uyumludur F :In an unsafe context, a method M is compatible with a function pointer type F if all of the following are true:
M``Faynı sayıda parametreye sahiptir ve içindeki her bir parametreMrefoutiniçindeki karşılık gelen parametresiyle aynı, veya değiştiricilere sahiptirF.MandFhave the same number of parameters, and each parameter inMhas the sameref,out, orinmodifiers as the corresponding parameter inF.- Her bir değer parametresi (Hayır
ref, veya değiştirici içeren bir parametreout) içinin, bir kimlik dönüştürme, örtük başvuru dönüştürme veya içindeki parametre türünden ' de karşılık gelen parametre türüne sahip örtülü işaretçi dönüştürme bulunurMF.For each value parameter (a parameter with noref,out, orinmodifier), an identity conversion, implicit reference conversion, or implicit pointer conversion exists from the parameter type inMto the corresponding parameter type inF. - Her
ref,outveya parametresi içininiçindeki parametre türü,Miçindeki karşılık gelen parametre türüyle aynıdırF.For eachref,out, orinparameter, the parameter type inMis the same as the corresponding parameter type inF. - Dönüş türü değer (Hayır
refveyaref readonly) ise, bir kimlik, örtük başvuru veya dönüş türünden dönüş türüne örtülü bir işaretçi dönüştürmesi vardırFM.If the return type is by value (noreforref readonly), an identity, implicit reference, or implicit pointer conversion exists from the return type ofFto the return type ofM. - Dönüş türü başvuruya (veya) göre ise
refref readonly, dönüş türü verefdeğiştiriciler,Fdönüş türü verefdeğiştiricilerine benzerM.If the return type is by reference (reforref readonly), the return type andrefmodifiers ofFare the same as the return type andrefmodifiers ofM. - Çağırma kuralı,
Mçağırma kuralıyla aynıdırF.The calling convention ofMis the same as the calling convention ofF. Bu hem çağırma kuralı bitini hem de yönetilmeyen tanımlayıcıda belirtilen tüm çağırma kuralı bayraklarını içerir.This includes both the calling convention bit, as well as any calling convention flags specified in the unmanaged identifier. Mstatik bir yöntemdir.Mis a static method.
Güvenli olmayan bir bağlamda, hedefi bir yöntem grubu olan bir adres ifadeden, E F Bu, E kendi normal biçiminde geçerli olan en az bir yöntemi F , aşağıdaki bölümünde açıklandığı gibi parametre türleri ve değiştiriciler kullanılarak oluşturulan bir bağımsız değişken listesine sahiptirIn an unsafe context, an implicit conversion exists from an address-of expression whose target is a method group E to a compatible function pointer type F if E contains at least one method that is applicable in its normal form to an argument list constructed by use of the parameter types and modifiers of F, as described in the following.
MAşağıdaki değişikliklerle formun yöntem çağrısına karşılık gelen tek bir yöntem seçilirE(A):A single methodMis selected corresponding to a method invocation of the formE(A)with the following modifications:- Bağımsız değişkenler listesi
A, her biri bir değişken olarak sınıflandırılan verefoutinkarşılık gelen funcptr _ parametre _ listesinin türü ve değiştiricisi (,, veya) içeren bir ifadeler listesidirF.The arguments listAis a list of expressions, each classified as a variable and with the type and modifier (ref,out, orin) of the corresponding funcptr_parameter_list ofF. - Aday Yöntemler, genişletilmiş biçiminde uygulananlar değil, yalnızca normal biçimlerinde geçerli olan yöntemlerdir.The candidate methods are only those methods that are applicable in their normal form, not those applicable in their expanded form.
- Aday yöntemler yalnızca statik olan yöntemlerdir.The candidate methods are only those methods that are static.
- Bağımsız değişkenler listesi
- Aşırı yükleme çözümlemesi algoritması bir hata üretirse, derleme zamanı hatası oluşur.If the algorithm of overload resolution produces an error, then a compile-time error occurs. Aksi takdirde, algoritma aynı sayıda parametreye sahip tek bir en iyi yöntem üretir
MFve dönüştürme var olarak kabul edilir.Otherwise, the algorithm produces a single best methodMhaving the same number of parameters asFand the conversion is considered to exist. - Seçilen yöntem,
Mişlev işaretçisi türü ile uyumlu olmalıdır (yukarıda tanımlandığı gibi)F.The selected methodMmust be compatible (as defined above) with the function pointer typeF. Aksi takdirde, bir derleme zamanı hatası oluşur.Otherwise, a compile-time error occurs. - Dönüştürmenin sonucu, türünde bir işlev işaretçisidir
F.The result of the conversion is a function pointer of typeF.
Bu, geliştiricilerin adres operatörü ile birlikte çalışmak için aşırı yükleme çözümleme kurallarına bağlı olabileceği anlamına gelir:This means developers can depend on overload resolution rules to work in conjunction with the address-of operator:
unsafe class Util {
public static void Log() { }
public static void Log(string p1) { }
public static void Log(int i) { };
void Use() {
delegate*<void> a1 = &Log; // Log()
delegate*<int, void> a2 = &Log; // Log(int i)
// Error: ambiguous conversion from method group Log to "void*"
void* v = &Log;
}
Address-of işleci, yönergesi kullanılarak uygulanır ldftn .The address-of operator will be implemented using the ldftn instruction.
Bu özelliğin kısıtlamaları:Restrictions of this feature:
- Yalnızca olarak işaretlenen yöntemler için geçerlidir
static.Only applies to methods marked asstatic. - Yerel olmayan
staticişlevler içinde kullanılamaz&.Non-staticlocal functions cannot be used in&. Bu yöntemlerin uygulama ayrıntıları, dil tarafından kasıtlı olarak belirtilmez.The implementation details of these methods are deliberately not specified by the language. Bu, statik ve örnek veya tam olarak hangi imzayı yayındıklarınızı içerir.This includes whether they are static vs. instance or exactly what signature they are emitted with.
Işlev Işaretçisi türlerindeki işleçlerOperators on Function Pointer Types
İşleçleri üzerinde güvenli olmayan kod bölümünde şu şekilde değişiklik yapılır:The section in unsafe code on operators is modified as such:
Güvenli olmayan bir bağlamda, _funcptr type_s olmayan tüm _pointer type_s üzerinde çalışan birkaç yapı mevcuttur _ _ :In an unsafe context, several constructs are available for operating on all _pointer_type_s that are not _funcptr_type_s:
*İşleci işaretçi yöneltme (işaretçi yöneltme) yapmak için kullanılabilir.The*operator may be used to perform pointer indirection (Pointer indirection).- İşleci, bir
->yapının üyesine işaretçi aracılığıyla erişmek için kullanılabilir (işaretçi üyesi erişimi).The->operator may be used to access a member of a struct through a pointer (Pointer member access).[]İşleci bir işaretçiye dizin eklemek için kullanılabilir (işaretçi öğesi erişimi).The[]operator may be used to index a pointer (Pointer element access).&İşleci bir değişkenin adresini (Adres operatörü) almak için kullanılabilir.The&operator may be used to obtain the address of a variable (The address-of operator).++Ve--işleçleri, işaretçileri artırmak ve azaltmak için kullanılabilir (işaretçi artışı ve azaltma).The++and--operators may be used to increment and decrement pointers (Pointer increment and decrement).+Ve-işleçleri, işaretçi aritmetiği (işaretçi aritmetiği) gerçekleştirmek için kullanılabilir.The+and-operators may be used to perform pointer arithmetic (Pointer arithmetic).- ,,,,
==!=<><=Ve=>işleçleri işaretçileri karşılaştırmak için kullanılabilir (işaretçi karşılaştırması).The==,!=,<,>,<=, and=>operators may be used to compare pointers (Pointer comparison).stackallocİşleç, çağrı yığınından bellek ayırmak için kullanılabilir (sabit boyutlu arabellekler).Thestackallocoperator may be used to allocate memory from the call stack (Fixed size buffers).- Bu
fixedifade, bir değişkeni geçici olarak çözmek için kullanılabilir ve bu nedenle adresi elde edilebilir (fixed deyimidir).Thefixedstatement may be used to temporarily fix a variable so its address can be obtained (The fixed statement).Güvenli olmayan bir bağlamda, tüm _funcptr type_s için çeşitli yapılar kullanılabilir _ :In an unsafe context, several constructs are available for operating on all _funcptr_type_s:
&İşleci, statik yöntemlerin adresini elde etmek için kullanılabilir (hedef yöntemlere yönelik adrese izin ver)The&operator may be used to obtain the address of static methods (Allow address-of to target methods)- ,,,,
==!=<><=Ve=>işleçleri işaretçileri karşılaştırmak için kullanılabilir (işaretçi karşılaştırması).The==,!=,<,>,<=, and=>operators may be used to compare pointers (Pointer comparison).
Ayrıca, içindeki tüm bölümleri Pointers in expressions , ve dışında fordeklarasyon işlev işaretçisi türlerine değiştiririz Pointer comparison The sizeof operator .Additionally, we modify all the sections in Pointers in expressions to forbid function pointer types, except Pointer comparison and The sizeof operator.
Daha iyi işlev üyesiBetter function member
Daha iyi işlev üyesi belirtimi aşağıdaki satırı içerecek şekilde değiştirilecek:The better function member specification will be changed to include the following line:
delegate*, Şundan daha belirginvoid*Adelegate*is more specific thanvoid*
Diğer bir deyişle, ve ' de aşırı yükleme yapılabilir void* delegate* ve yine de sensibly adres işlecini kullanabilirsiniz.This means that it is possible to overload on void* and a delegate* and still sensibly use the address-of operator.
Tür ÇıkarmaType Inference
Güvenli olmayan kodda, tür çıkarımı algoritmalarında aşağıdaki değişiklikler yapılmıştır:In unsafe code, the following changes are made to the type inference algorithms:
Giriş türleriInput types
https://github.com/dotnet/csharplang/blob/master/spec/expressions.md#input-types
Aşağıdakiler eklenmiştir:The following is added:
Eğer bir
EYöntem grubudur veTbir işlev işaretçisi türü ise, öğesinin tüm parametre türleriTtüründe giriş türleridirET.IfEis an address-of method group andTis a function pointer type then all the parameter types ofTare input types ofEwith typeT.
Çıkış türleriOutput types
https://github.com/dotnet/csharplang/blob/master/spec/expressions.md#output-types
Aşağıdakiler eklenmiştir:The following is added:
Eğer bir
EYöntem grubu ise veTbir işlev işaretçisi türü ise, öğesinin dönüş türüTtüründe bir çıkış türüdürET.IfEis an address-of method group andTis a function pointer type then the return type ofTis an output type ofEwith typeT.
Çıkış türü ındaOutput type inferences
https://github.com/dotnet/csharplang/blob/master/spec/expressions.md#output-type-inferences
2 ve 3 ' ün arasına aşağıdaki madde işareti eklenir:The following bullet is added between bullets 2 and 3:
- ,
EBir adres yöntemi grubudur veTparametre türleri ve dönüş türü olan bir işlev işaretçisi türüdürT1...TkTbve türleri ile aşırı yükleme çözümlemesi,ET1..Tkdönüş türü ile tek bir yöntem alıyorsaU, ' den ' e daha düşük bağlantılı bir çıkarım yapılırUTb.IfEis an address-of method group andTis a function pointer type with parameter typesT1...Tkand return typeTb, and overload resolution ofEwith the typesT1..Tkyields a single method with return typeU, then a lower-bound inference is made fromUtoTb.
Tam ındaExact inferences
https://github.com/dotnet/csharplang/blob/master/spec/expressions.md#exact-inferences
Aşağıdaki alt madde işareti 2 ' ye işaret eden bir durum olarak eklenir:The following sub-bullet is added as a case to bullet 2:
Vbir işlev işaretçisi türüdürdelegate*<V2..Vk, V1>veUbir işlev işaretçisi türüdür ve 'delegate*<U2..Uk, U1>ın çağırma kuralı ile aynıdırVUve ' ın ' i ileViaynıdırUi.Vis a function pointer typedelegate*<V2..Vk, V1>andUis a function pointer typedelegate*<U2..Uk, U1>, and the calling convention ofVis identical toU, and the refness ofViis identical toUi.
Alt sınırLower-bound inferences
https://github.com/dotnet/csharplang/blob/master/spec/expressions.md#lower-bound-inferences
Aşağıdaki durum 3 madde işaretine eklenmiştir:The following case is added to bullet 3:
Vbir işlev işaretçisi türüdürdelegate*<V2..Vk, V1>ve ile özdeş olan bir işlev işaretçisi türü vardır ve 'delegate*<U2..Uk, U1>Udelegate*<U2..Uk, U1>ın çağırma kuralıVUViUiile aynıdır.Vis a function pointer typedelegate*<V2..Vk, V1>and there is a function pointer typedelegate*<U2..Uk, U1>such thatUis identical todelegate*<U2..Uk, U1>, and the calling convention ofVis identical toU, and the refness ofViis identical toUi.
Öğesinden çıkarım ilk madde işareti Ui Vi Şu şekilde değiştirilir:The first bullet of inference from Ui to Vi is modified to:
UBir işlev işaretçisi türü değildir ve birUibaşvuru türü olarak bilinmez ya daUbir işlev işaretçisi türü ise ve birUiişlev işaretçisi türü veya başvuru türü olarak bilinmiyorsa, tam bir çıkarım yapılırIfUis not a function pointer type andUiis not known to be a reference type, or ifUis a function pointer type andUiis not known to be a function pointer type or a reference type, then an exact inference is made
Ardından, öğesinden çıkarım öğesinden sonra Ui Vi :Then, added after the 3rd bullet of inference from Ui to Vi:
- Aksi takdirde,
Vdelegate*<V2..Vk, V1>çıkarımı t-TH parametresine bağlıdırdelegate*<V2..Vk, V1>:Otherwise, ifVisdelegate*<V2..Vk, V1>then inference depends on the i-th parameter ofdelegate*<V2..Vk, V1>:
- V1:If V1:
- Dönüş değere göre ise, alt sınır çıkarımı yapılır.If the return is by value, then a lower-bound inference is made.
- Dönüş başvuruya göre ise, kesin bir çıkarım yapılır.If the return is by reference, then an exact inference is made.
- V2... VKIf V2..Vk:
- Parametre değere göre ise, üst sınır çıkarımı yapılır.If the parameter is by value, then an upper-bound inference is made.
- Parametre başvuruya göre ise, kesin bir çıkarım yapılır.If the parameter is by reference, then an exact inference is made.
Üst sınırUpper-bound inferences
https://github.com/dotnet/csharplang/blob/master/spec/expressions.md#upper-bound-inferences
Aşağıdaki örnek, 2. madde işaretine eklenmiştir:The following case is added to bullet 2:
U, bir işlev işaretçisi türüdürdelegate*<U2..Uk, U1>ve ileVözdeş olan bir işlev işaretçisi türüdür ve ' nin, ile aynı,delegate*<V2..Vk, V1>UV'UiVinin de aynısı ile aynıdır.Uis a function pointer typedelegate*<U2..Uk, U1>andVis a function pointer type which is identical todelegate*<V2..Vk, V1>, and the calling convention ofUis identical toV, and the refness ofUiis identical toVi.
Öğesinden çıkarım ilk madde işareti Ui Vi Şu şekilde değiştirilir:The first bullet of inference from Ui to Vi is modified to:
UBir işlev işaretçisi türü değildir ve birUibaşvuru türü olarak bilinmez ya daUbir işlev işaretçisi türü ise ve birUiişlev işaretçisi türü veya başvuru türü olarak bilinmiyorsa, tam bir çıkarım yapılırIfUis not a function pointer type andUiis not known to be a reference type, or ifUis a function pointer type andUiis not known to be a function pointer type or a reference type, then an exact inference is made
Ardından, öğesinden çıkarım öğesinden sonra Ui Vi :Then added after the 3rd bullet of inference from Ui to Vi:
- Aksi takdirde,
Udelegate*<U2..Uk, U1>çıkarımı t-TH parametresine bağlıdırdelegate*<U2..Uk, U1>:Otherwise, ifUisdelegate*<U2..Uk, U1>then inference depends on the i-th parameter ofdelegate*<U2..Uk, U1>:
- Eğer U1:If U1:
- Dönüş değere göre ise, üst sınır çıkarımı yapılır.If the return is by value, then an upper-bound inference is made.
- Dönüş başvuruya göre ise, kesin bir çıkarım yapılır.If the return is by reference, then an exact inference is made.
- Eğer U2... TrIf U2..Uk:
- Parametre değere göre ise, alt sınır çıkarımı yapılır.If the parameter is by value, then a lower-bound inference is made.
- Parametre başvuruya göre ise, kesin bir çıkarım yapılır.If the parameter is by reference, then an exact inference is made.
in, out , Ve ref readonly parametrelerinin ve dönüş türlerinin meta veri temsiliMetadata representation of in, out, and ref readonly parameters and return types
İşlev işaretçisi imzalarının parametre bayrakları konumu yok, bu nedenle parametre ve dönüş türünün in ,, out veya ref readonly modreqs kullanarak kodlanması gerekir.Function pointer signatures have no parameter flags location, so we must encode whether parameters and the return type are in, out, or ref readonly by using modreqs.
in
System.Runtime.InteropServices.InAttributeBir modreq parametre ya da dönüş türü üzerinde başvuru belirticisine bir olarak, aşağıdaki gibi bir değer olarak uygulandıktan sonra yeniden kullanıyoruz:We reuse System.Runtime.InteropServices.InAttribute, applied as a modreq to the ref specifier on a parameter or return type, to mean the following:
- Bir parametre başvurusu belirticisine uygulanmışsa, bu parametre olarak değerlendirilir
in.If applied to a parameter ref specifier, this parameter is treated asin. - Dönüş türü başvuru belirticisine uygulanmışsa, dönüş türü olarak değerlendirilir
ref readonly.If applied to the return type ref specifier, the return type is treated asref readonly.
out
Parametresi bir parametre System.Runtime.InteropServices.OutAttribute modreq olduğu anlamına gelen bir parametre türü üzerinde başvuru belirleyicisi olarak uygulandı out .We use System.Runtime.InteropServices.OutAttribute, applied as a modreq to the ref specifier on a parameter type, to mean that the parameter is an out parameter.
HatalarErrors
OutAttributeBir dönüş türüne modreq olarak uygulanması hatadır.It is an error to applyOutAttributeas a modreq to a return type.- Hem hem de bir
InAttributeOutAttributeparametre türüne modreq olarak uygulamak hatadır.It is an error to apply bothInAttributeandOutAttributeas a modreq to a parameter type. - Her biri modopt ile belirtilirse, bunlar yoksayılır.If either are specified via modopt, they are ignored.
Çağırma kurallarının meta veri temsiliMetadata Representation of Calling Conventions
Çağırma kuralları, İmzadaki bayrağın bir birleşimi ile meta verilerde bir yöntem imzasında kodlanır CallKind ve imzanın başlangıcında sıfır veya daha fazla modopt s.Calling conventions are encoded in a method signature in metadata by a combination of the CallKind flag in the signature and zero or more modopts at the start of the signature. ECMA-335 Şu anda bayrakta aşağıdaki öğeleri bildiriyor CallKind :ECMA-335 currently declares the following elements in the CallKind flag:
CallKind
: default
| unmanaged cdecl
| unmanaged fastcall
| unmanaged thiscall
| unmanaged stdcall
| varargs
;
Bunlar, C# ' deki işlev işaretçileri, ancak tümünü destekleyecektir varargs .Of these, function pointers in C# will support all but varargs.
Ayrıca, çalışma zamanı (ve sonuç olarak 335) yeni platformları kapsayacak şekilde güncelleştirilecektir CallKind .In addition, the runtime (and eventually 335) will be updated to include a new CallKind on new platforms. Bu, şu anda resmi bir ada sahip değil, ancak bu belge unmanaged ext yeni Genişletilebilir çağırma kuralı biçimi için tek bir yer tutucu olarak kullanılacak.This does not have a formal name currently, but this document will use unmanaged ext as a placeholder to stand for the new extensible calling convention format. Her ikisi de, modopt unmanaged ext unmanaged köşeli parantezler olmadan platform varsayılan çağırma kuralıdır.With no modopts, unmanaged ext is the platform default calling convention, unmanaged without the square brackets.
İle arasında eşleme calling_convention_specifier``CallKindMapping the calling_convention_specifier to a CallKind
calling_convention_specifierAtlanan veya olarak belirtilen bir, managed ile eşlenir default CallKind .A calling_convention_specifier that is omitted, or specified as managed, maps to the default CallKind. Bu, öğesine CallKind sahip olmayan her yöntemin varsayılandır UnmanagedCallersOnly .This is default CallKind of any method not attributed with UnmanagedCallersOnly.
C#, ECMA 335 ' den mevcut olan yönetilmeyen s 'lerden eşlenen 4 özel tanımlayıcıyı tanır CallKind .C# recognizes 4 special identifiers that map to specific existing unmanaged CallKinds from ECMA 335. Bu eşlemenin gerçekleşmesi için, bu tanımlayıcıların başka tanımlayıcı olmadan, kendi üzerinde belirtilmesi gerekir ve bu gereksinim, s için spec olarak kodlanır unmanaged_calling_convention .In order for this mapping to occur, these identifiers must be specified on their own, with no other identifiers, and this requirement is encoded into the spec for unmanaged_calling_conventions. Bu tanımlayıcılar,,, ve sırasıyla,,, Cdecl Thiscall Stdcall Fastcall unmanaged cdecl unmanaged thiscall unmanaged stdcall ve ' a karşılık gelen unmanaged fastcall ,, ve.These identifiers are Cdecl, Thiscall, Stdcall, and Fastcall, which correspond to unmanaged cdecl, unmanaged thiscall, unmanaged stdcall, and unmanaged fastcall, respectively. Birden fazla identifer belirtilirse veya tek identifier özel tanınan tanımlayıcılardan değilse, tanımlayıcıda aşağıdaki kurallara sahip özel ad araması yaptık:If more than one identifer is specified, or the single identifier is not of the specially recognized identifiers, we perform special name lookup on the identifier with the following rules:
- Dizeden sonuna kadar
identifier``CallConvWe prepend theidentifierwith the stringCallConv - Yalnızca ad alanında tanımlanan türlere bakacağız
System.Runtime.CompilerServices.We look only at types defined in theSystem.Runtime.CompilerServicesnamespace. - Yalnızca uygulamanın çekirdek kitaplığında tanımlı türlere göz atacağız. Bu kitaplık, tanımlayan ve bağımlılığı olmayan bir kitaplıktır
System.Object.We look only at types defined in the core library of the application, which is the library that definesSystem.Objectand has no dependencies. - Yalnızca ortak türlere baktık.We look only at public types.
Arama, identifier bir içinde belirtilen tüm öğeleri üzerinde başarılı olursa, unmanaged_calling_convention as olarak kodlarız CallKind unmanaged ext ve modopt işlev işaretçisi imzasının başlangıcında bulunan her bir çözümlenmiş türü kodlayın.If lookup succeeds on all of the identifiers specified in an unmanaged_calling_convention, we encode the CallKind as unmanaged ext, and encode each of the resolved types in the set of modopts at the beginning of the function pointer signature. Bir notta, bu kurallar identifier , kullanıcıların aramaya yol açacak şekilde bu öğeleri uygulamasına ön eki gerçekleştiremediğini ifade CallConv eder CallConvCallConvVectorCall .As a note, these rules mean that users cannot prefix these identifiers with CallConv, as that will result in looking up CallConvCallConvVectorCall.
Meta verileri yorumlarken, ilk olarak konusuna baktık CallKind .When interpreting metadata, we first look at the CallKind. ' Den başka bir şey ise unmanaged ext , modopt çağırma kuralını belirleme ve yalnızca öğesini kullanma amacıyla, dönüş türündeki tüm öğeleri yok sayıyoruz CallKind .If it is anything other than unmanaged ext, we ignore all modopts on the return type for the purposes of determining the calling convention, and use only the CallKind. İse, CallKind unmanaged ext işlev işaretçisi türünün başlangıcında, aşağıdaki gereksinimleri karşılayan tüm türlerin birleşimini alarak modopts ' a bakacağız:If the CallKind is unmanaged ext, we look at the modopts at the start of the function pointer type, taking the union of all types that meet the following requirements:
- , Başka bir kitaplıklara ve tanımlanmadığında, kitaplık olan Çekirdek Kitaplığı 'nda tanımlanmıştır
System.Object.The is defined in the core library, which is the library that references no other libraries and definesSystem.Object. - Tür
System.Runtime.CompilerServicesad alanında tanımlanır.The type is defined in theSystem.Runtime.CompilerServicesnamespace. - Tür önekiyle başlar
CallConv.The type starts with the prefixCallConv. - Tür geneldir.The type is public.
Bunlar, identifier unmanaged_calling_convention kaynakta bir işlev işaretçisi türü tanımlarken bir üzerinde arama gerçekleştirirken bulunması gereken türleri temsil eder.These represent the types that must be found when performing lookup on the identifiers in an unmanaged_calling_convention when defining a function pointer type in source.
CallKind unmanaged ext Hedef çalışma zamanı özelliği desteklemiyorsa, ile bir işlev işaretçisi kullanma girişimi bir hatadır.It is an error to attempt to use a function pointer with a CallKind of unmanaged ext if the target runtime does not support the feature. Bu işlem, sabit varlığına bakılarak belirlenir System.Runtime.CompilerServices.RuntimeFeature.UnmanagedCallKind .This will be determined by looking for the presence of the System.Runtime.CompilerServices.RuntimeFeature.UnmanagedCallKind constant. Bu sabit varsa, çalışma zamanı özelliği desteklemek için kabul edilir.If this constant is present, the runtime is considered to support the feature.
System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute
System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute , bir yöntemin belirli bir çağırma kuralıyla çağrılması gerektiğini göstermek için CLR tarafından kullanılan bir özniteliktir.System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute is an attribute used by the CLR to indicate that a method should be called with a specific calling convention. Bu nedenle, özniteliğiyle çalışma için aşağıdaki desteği sunuyoruz:Because of this, we introduce the following support for working with the attribute:
- C# ' den bu öznitelikle açıklanmış bir yöntemi doğrudan çağırmak hatadır.It is an error to directly call a method annotated with this attribute from C#. Kullanıcılar yöntemine bir işlev işaretçisi almalıdır ve sonra bu işaretçiyi çağırmalıdır.Users must obtain a function pointer to the method and then invoke that pointer.
- Özniteliği sıradan statik bir yöntem veya sıradan statik yerel işlev dışında bir şeye uygulamak hatadır.It is an error to apply the attribute to anything other than an ordinary static method or ordinary static local function. C# derleyicisi, Bu öznitelikle meta verilerden içeri aktarılan statik olmayan veya statik olmayan, normal olmayan yöntemlerin dilini tarafından desteklenmeyen şekilde işaretleyecek.The C# compiler will mark any non-static or static non-ordinary methods imported from metadata with this attribute as unsupported by the language.
- Özniteliği ile işaretlenmiş ve bir parametre ya da dönüş türü olmayan bir yöntem için bir hatadır
unmanaged_type.It is an error for a method marked with the attribute to have a parameter or return type that is not anunmanaged_type. - Bu tür parametreleri ile kısıtlansa bile, öznitelik ile işaretlenmiş bir yöntemin tür parametrelerine sahip olması hatadır
unmanaged.It is an error for a method marked with the attribute to have type parameters, even if those type parameters are constrained tounmanaged. - Bu, genel türdeki bir yöntemin özniteliğiyle işaretlenmesi hatadır.It is an error for a method in a generic type to be marked with the attribute.
- Özniteliği ile işaretlenmiş bir yöntemi temsilci türüne dönüştürmek hatadır.It is an error to convert a method marked with the attribute to a delegate type.
UnmanagedCallersOnly.CallConvsMeta verilerde, kuralları çağırma gereksinimlerini karşılamayan herhangi bir tür belirtmek bir hatadırmodopt.It is an error to specify any types forUnmanagedCallersOnly.CallConvsthat do not meet the requirements for calling conventionmodopts in metadata.
Geçerli bir öznitelik ile işaretlenmiş bir yöntemin çağırma kuralını belirlerken UnmanagedCallersOnly , derleyici, CallConvs CallKind modopt çağırma kuralını belirlemek için kullanılması gereken geçerli ve s 'yi belirlemek için özelliğinde belirtilen türler üzerinde aşağıdaki denetimleri gerçekleştirir:When determining the calling convention of a method marked with a valid UnmanagedCallersOnly attribute, the compiler performs the following checks on the types specified in the CallConvs property to determine the effective CallKind and modopts that should be used to determine the calling convention:
- Hiçbir tür belirtilmemişse,
CallKindunmanaged extmodoptişlev işaretçisi türünün başlangıcında hiçbir çağırma kuralı olmadan olarak değerlendirilir.If no types are specified, theCallKindis treated asunmanaged ext, with no calling conventionmodopts at the start of the function pointer type. - Bir tür belirtilmişse ve bu tür,, veya olarak adlandırılmışsa
CallConvCdecl,CallConvThiscallCallConvStdcallCallConvFastcallCallKindunmanaged cdeclunmanaged thiscallunmanaged stdcallunmanaged fastcallmodoptişlev işaretçisi türünün başlangıcında hiçbir çağırma kuralı olmadan,,, veya olarak değerlendirilir.If there is one type specified, and that type is namedCallConvCdecl,CallConvThiscall,CallConvStdcall, orCallConvFastcall, theCallKindis treated asunmanaged cdecl,unmanaged thiscall,unmanaged stdcall, orunmanaged fastcall, respectively, with no calling conventionmodopts at the start of the function pointer type. - Birden çok tür belirtilmişse veya tek tür Yukarıdaki özel olarak çağrılan çıkış türlerinden biri olarak adlandırılmışsa,
CallKindunmanaged extmodoptişlev işaretçisi türünün başlangıcında, belirtilen türlerin birleşimi ile olarak değerlendirilir.If multiple types are specified or the single type is not named one of the specially called out types above, theCallKindis treated asunmanaged ext, with the union of the types specified treated asmodopts at the start of the function pointer type.
Daha sonra derleyici bu etkin CallKind ve koleksiyona bakar modopt ve işlev işaretçisi türünün son çağırma kuralını belirlemede normal meta veri kurallarını kullanır.The compiler then looks at this effective CallKind and modopt collection and uses normal metadata rules to determine the final calling convention of the function pointer type.
Açık Uçlu SorularOpen Questions
İçin çalışma zamanı desteği algılanıyor unmanaged extDetecting runtime support for unmanaged ext
https://github.com/dotnet/runtime/issues/38135 Bu bayrağı eklemeyi izler.https://github.com/dotnet/runtime/issues/38135 tracks adding this flag. Gözden geçirimden geri bildirime bağlı olarak, sorun içinde belirtilen özelliğini kullanacağız veya çalışma UnmanagedCallersOnlyAttribute zamanlarının destekleyip desteklemediğini belirleyen bayrak olarak varlığını kullanın unmanaged ext .Depending on the feedback from review, we will either use the property specified in the issue, or use the presence of UnmanagedCallersOnlyAttribute as the flag that determines whether the runtimes supports unmanaged ext.
Dikkat edilmesi gerekenlerConsiderations
Örnek yöntemlerine izin verAllow instance methods
Teklif, EXPLICITTHIS CLI çağırma kuralı (C# kodunda adlandırılmış olarak adlandırılır) avantajlarından yararlanarak örnek yöntemlerini desteklemek için Genişletilebilir instance .The proposal could be extended to support instance methods by taking advantage of the EXPLICITTHIS CLI calling convention (named instance in C# code). CLı işlev işaretçilerinden oluşan bu form, this parametreyi işlev işaretçisi sözdiziminin açık bir ilk parametresi olarak koyar.This form of CLI function pointers puts the this parameter as an explicit first parameter of the function pointer syntax.
unsafe class Instance {
void Use() {
delegate* instance<Instance, string> f = &ToString;
f(this);
}
}
Bu ses, ancak teklife bazı karmaşıkma ekler.This is sound but adds some complication to the proposal. Özellikle, çağırma kuralı tarafından farklı olan instance ve managed her iki durum da aynı C# imzasıyla yönetilen yöntemleri çağırmak için kullanılan işlev işaretçileri nedeniyle uyumsuz olacak şekilde,Particularly because function pointers which differed by the calling convention instance and managed would be incompatible even though both cases are used to invoke managed methods with the same C# signature. Her durumda, bu durumun basit bir iş olması için değerli olduğu kabul edilir: static yerel bir işlev kullanın.Also in every case considered where this would be valuable to have there was a simple work around: use a static local function.
unsafe class Instance {
void Use() {
static string toString(Instance i) => i.ToString();
delegate*<Instance, string> f = &toString;
f(this);
}
}
Bildirimde güvenli olmayan isteDon't require unsafe at declaration
unsafeHer bir kullanımını gerektirmek yerine delegate* , yalnızca bir yöntem grubunun öğesine dönüştürüldüğü noktada bunu gerektir delegate* .Instead of requiring unsafe at every use of a delegate*, only require it at the point where a method group is converted to a delegate*. Bu, temel güvenlik sorunlarının oynatılmasına (değer etkin olduğu sürece kapsayan derlemenin kaldırılamayacağını bilmek) neden olur.This is where the core safety issues come into play (knowing that the containing assembly cannot be unloaded while the value is alive). unsafeDiğer konumlar için ihtiyaç duyulmaları çok fazla olabilir.Requiring unsafe on the other locations can be seen as excessive.
Tasarımın ilk amacı budur.This is how the design was originally intended. Ancak elde edilen dil kuralları, çok daha fazla.But the resulting language rules felt very awkward. Bu bir işaretçi değeri olduğu ve anahtar sözcüğü olmadan bile üzerinde gezindiğinden emin olmak mümkün değildir unsafe .It's impossible to hide the fact that this is a pointer value and it kept peeking through even without the unsafe keyword. Örneğin dönüştürmeye object izin verilmiyorsa, class , vb. bir üyesi olamaz. C# tasarımı unsafe Tüm işaretçinin kullanması için ve bu tasarımın bundan sonra bunu takip etmek için gereklidir.For example the conversion to object can't be allowed, it can't be a member of a class, etc ... The C# design is to require unsafe for all pointer uses and hence this design follows that.
Geliştiriciler yine de delegate* normal işaretçi türlerinde gerçekleştirdikleri şekilde, değerlerin üzerine güvenli bir sarmalayıcı sunma yeteneğine sahip olmaya devam edecektir.Developers will still be capable of presenting a safe wrapper on top of delegate* values the same way that they do for normal pointer types today. Aşağıdakileri dikkate alın:Consider:
unsafe struct Action {
delegate*<void> _ptr;
Action(delegate*<void> ptr) => _ptr = ptr;
public void Invoke() => _ptr();
}
Temsilcileri kullanmaUsing delegates
Yeni bir sözdizimi öğesi kullanmak yerine, delegate* mevcut delegate türleri aşağıdaki türle birlikte kullanmanız yeterlidir * :Instead of using a new syntax element, delegate*, simply use existing delegate types with a * following the type:
Func<object, object, bool>* ptr = &object.ReferenceEquals;
Çağırma kuralını işleme, delegate bir değeri belirten bir özniteliğe sahip türlere açıklama eklenerek yapılabilir CallingConvention .Handling calling convention can be done by annotating the delegate types with an attribute that specifies a CallingConvention value. Bir özniteliğin olmaması yönetilen çağırma kuralını işaret eder.The lack of an attribute would signify the managed calling convention.
Il 'de bunu kodlamada sorun vardır.Encoding this in IL is problematic. Temel alınan değerin bir işaretçi olarak temsil edilebilmesi için yine de şunları yapmanız gerekir:The underlying value needs to be represented as a pointer yet it also must:
- Farklı işlev işaretçisi türleri olan aşırı yüklemelerin izin vermek için benzersiz bir türü vardır.Have a unique type to allow for overloads with different function pointer types.
- Derleme sınırları genelinde OHI amaçları için eşdeğer olmalıdır.Be equivalent for OHI purposes across assembly boundaries.
Son nokta özellikle sorunlu.The last point is particularly problematic. Bu, kullanan her derlemenin, Func<int>* Func<int>* bir derlemede tanımlansa bile, meta verilerde eşdeğer bir tür kodlanması gereken anlamına gelir.This mean that every assembly which uses Func<int>* must encode an equivalent type in metadata even though Func<int>* is defined in an assembly though don't control.
Ayrıca System.Func<T> , mscorlib olmayan bir derlemede tanımlanan diğer herhangi bir tür, mscorlib 'de tanımlanan sürümden farklı olmalıdır.Additionally any other type which is defined with the name System.Func<T> in an assembly that is not mscorlib must be different than the version defined in mscorlib.
Araştırılan bir seçenek bu tür bir işaretçiyi gibi yaymıştı mod_req(Func<int>) void* .One option that was explored was emitting such a pointer as mod_req(Func<int>) void*. Bir mod_req öğesine bağlanamaz TypeSpec ve bu nedenle genel örneklemeleri hedeflenemez.This doesn't work though as a mod_req cannot bind to a TypeSpec and hence cannot target generic instantiations.
Adlandırılmış işlev işaretçileriNamed function pointers
İşlev işaretçisi sözdizimi, özellikle de iç içe geçmiş işlev işaretçileri gibi karmaşık durumlarda, kısabera olabilir.The function pointer syntax can be cumbersome, particularly in complex cases like nested function pointers. Geliştiricilerin, ile yapıldığı gibi işlev işaretçilerinin adlandırılmış bildirimleri için izin verebilen her seferinde imzayı yazmak yerine delegateRather than have developers type out the signature every time the language could allow for named declarations of function pointers as is done with delegate.
func* void Action();
unsafe class NamedExample {
void M(Action a) {
a();
}
}
Sorunun bir bölümü, temel alınan CLı ilkel adının adı yoktur, bu nedenle yalnızca bir C# listesi olur ve bir bit meta veri işinin etkinleştirilmesini gerektirir.Part of the problem here is the underlying CLI primitive doesn't have names hence this would be purely a C# invention and require a bit of metadata work to enable. Bu, iş açısından önemli olan, ancak önemli bir çalışmadır.That is doable but is a significant about of work. Aslında C# ' ın yalnızca bu adlar için def tablosuna yönelik bir yardımcısı olmasını gerektirir.It essentially requires C# to have a companion to the type def table purely for these names.
Ayrıca, adlandırılmış işlev işaretçileri için bağımsız değişkenler incelendikleri zaman, diğer birçok senaryoya eşit bir şekilde uygulanamazlar.Also when the arguments for named function pointers were examined we found they could apply equally well to a number of other scenarios. Örneğin, tüm durumlarda tam imzayı yazma ihtiyacını azaltmak için adlandırılmış tanımlama gruplarını bildirmek uygun olabilir.For example it would be just as convenient to declare named tuples to reduce the need to type out the full signature in all cases.
(int x, int y) Point;
class NamedTupleExample {
void M(Point p) {
Console.WriteLine(p.x);
}
}
Tartışmadan sonra, türlerin adlandırılmış bildirimine izin vermeyi karardık delegate* .After discussion we decided to not allow named declaration of delegate* types. Bu, müşteri kullanımı geri bildirimlerine göre bu için önemli bir gereksinim olduğunu fark etmemiz halinde işlev işaretçileri, tanımlama grupları, genel türler, vb. için uygun bir adlandırma çözümü araştıracağız. Bu, formda tam destek gibi diğer önerilere benzer olabilir typedef .If we find there is significant need for this based on customer usage feedback then we will investigate a naming solution that works for function pointers, tuples, generics, etc ... This is likely to be similar in form to other suggestions like full typedef support in the language.
Gelecekteki konularFuture Considerations
statik temsilcilerstatic delegates
Bu, delegate yalnızca üyelere başvurabilen türlerin bildirimine izin veren öneriyi ifade eder static .This refers to the proposal to allow for the declaration of delegate types which can only refer to static members. Bu tür örneklerin avantajı, delegate performans duyarlı senaryolarda ücretsiz ve daha iyi bir şekilde tahsis edilebilir.The advantage being that such delegate instances can be allocation free and better in performance sensitive scenarios.
İşlev işaretçisi özelliği uygulanmışsa, static delegate teklif büyük olasılıkla kapatılmış olur. Bu özelliğin önerilen avantajı, ayırma ücretsiz doğası olur.If the function pointer feature is implemented the static delegate proposal will likely be closed out. The proposed advantage of that feature is the allocation free nature. Ancak son araştırmalar, derleme kaldırma işlemi nedeniyle elde edilebilecek mümkün olmayan bir şekilde bulundu.However recent investigations have found that is not possible to achieve due to assembly unloading. static delegateDerlemenin içinden bellekten kaldırılmasını önlemek için, öğesinden başvurduğu yönteme güçlü bir tanıtıcı olmalıdır.There must be a strong handle from the static delegate to the method it refers to in order to keep the assembly from being unloaded out from under it.
Her örneği sürdürmek için, static delegate teklifin hedeflerine sayaç çalıştıran yeni bir tanıtıcı ayrılması gerekir.To maintain every static delegate instance would be required to allocate a new handle which runs counter to the goals of the proposal. Ayırmanın çağrı-site başına tek bir ayırmaya salsatılabileceği, ancak bir bit karmaşıktı olduğu ve bu da ticareti kapatmasının gerektiği bazı tasarımlar vardı.There were some designs where the allocation could be amortized to a single allocation per call-site but that was a bit complex and didn't seem worth the trade off.
Diğer bir deyişle, geliştiriciler temelde aşağıdaki denge ile karar vermek zorunda değildir:That means developers essentially have to decide between the following trade offs:
- Derlemeyi kaldırma aşamasında güvenlik: Bu ayırmaları gerektirir ve bu nedenle
delegatezaten yeterli bir seçenektir.Safety in the face of assembly unloading: this requires allocations and hencedelegateis already a sufficient option. - Derleme kaldırma aşamasında güvenlik yok: bir kullanın
delegate*.No safety in face of assembly unloading: use adelegate*. Bu,structkodun geri kalanında bir bağlam dışında kullanılmasına izin vermek için bir öğesine kaydırılmış olabilirunsafe.This can be wrapped in astructto allow usage outside anunsafecontext in the rest of the code.