Function pointers - C# 9.0 specification proposals
文章推薦指數: 80 %
//This method has a managed calling convention. ... delegate Func1 Func2(Func1 f); // Function pointer equivalent without calling convention ...
跳到主要內容
已不再支援此瀏覽器。
請升級至MicrosoftEdge,以利用最新功能、安全性更新和技術支援。
下載MicrosoftEdge
其他資訊
目錄
結束焦點模式
閱讀英文
儲存
目錄
閱讀英文
儲存
編輯
Twitter
LinkedIn
Facebook
電子郵件
目錄
函式指標FunctionPointers
發行項
05/13/2021
2位參與者
本文內容
總結Summary
這份提案提供的語言結構,會公開目前無法有效存取的ILopcode,或目前在c#中的程式:ldftn和calli。
ThisproposalprovideslanguageconstructsthatexposeILopcodesthatcannotcurrentlybeaccessedefficiently,oratall,inC#today:ldftnandcalli.這些ILopcode在高效能的程式碼中可能很重要,而開發人員需要有效率的方式來存取它們。
TheseILopcodescanbeimportantinhighperformancecodeanddevelopersneedanefficientwaytoaccessthem.
動機Motivation
下列問題將說明這項功能的動機和背景,(為功能)的可能執行:Themotivationsandbackgroundforthisfeaturearedescribedinthefollowingissue(asisapotentialimplementationofthefeature):
https://github.com/dotnet/csharplang/issues/191
這是編譯器內建函式的替代設計提案Thisisanalternatedesignproposaltocompilerintrinsics
詳細設計DetailedDesign
函式指標Functionpointers
語言將允許使用語法來宣告函式指標delegate*。
Thelanguagewillallowforthedeclarationoffunctionpointersusingthedelegate*syntax.下一節會詳細描述完整的語法,但是它的目的是與和型別宣告所使用的語法類似FuncAction。
ThefullsyntaxisdescribedindetailinthenextsectionbutitismeanttoresemblethesyntaxusedbyFuncandActiontypedeclarations.
unsafeclassExample{
voidExample(Action
ThesetypesarerepresentedusingthefunctionpointertypeasoutlinedinECMA-335.這表示叫用將delegate*會使用calli,其中的調用delegate會callvirt在方法上使用Invoke。
Thismeansinvocationofadelegate*willusecalliwhereinvocationofadelegatewillusecallvirtontheInvokemethod.
在語法上,這兩個結構的調用完全相同。
Syntacticallythoughinvocationisidenticalforbothconstructs.
方法指標的ECMA-335定義包含做為類型簽章一部分的呼叫慣例,(區段7.1)。
TheECMA-335definitionofmethodpointersincludesthecallingconventionaspartofthetypesignature(section7.1).
預設呼叫慣例將為managed。
Thedefaultcallingconventionwillbemanaged.未受管理的呼叫慣例可以藉由unmanaged將關鍵字放afer語法來指定delegate*,這會使用執行時間平臺的預設值。
Unmanagedcallingconventionscanbyspecifiedbyputtinganunmanagedkeywordaferthedelegate*syntax,whichwillusetheruntimeplatformdefault.然後,您可以在命名空間中指定開頭為的任何類型,以括弧括住特定的非受控慣例unmanagedCallConvSystem.Runtime.CompilerServices,並保留CallConv前置詞。
SpecificunmanagedconventionscanthenbespecifiedinbracketstotheunmanagedkeywordbyspecifyinganytypestartingwithCallConvintheSystem.Runtime.CompilerServicesnamespace,leavingofftheCallConvprefix.這些類型必須來自于程式的核心程式庫,而有效組合的集合則與平臺相關。
Thesetypesmustcomefromtheprogram'scorelibrary,andthesetofvalidcombinationsisplatform-dependent.
//Thismethodhasamanagedcallingconvention.Thisisthesameasleavingthemanagedkeywordoff.
delegate*managed
Conversionsbetweendelegate*typesisdonebasedontheirsignatureincludingthecallingconvention.
unsafeclassExample{
voidConversions(){
delegate*
Onlyvalidinanunsafecontext.
delegate*只能從內容呼叫包含參數或傳回類型的方法unsafe。
Methodswhichcontainadelegate*parameterorreturntypecanonlybecalledfromanunsafecontext.
無法轉換成object。
Cannotbeconvertedtoobject.
無法當做泛型引數使用。
Cannotbeusedasagenericargument.
可以隱含地轉換delegate*成void*。
Canimplicitlyconvertdelegate*tovoid*.
可以明確地從轉換成void*delegate*。
Canexplicitlyconvertfromvoid*todelegate*.
限制:Restrictions:
自訂屬性無法套用至delegate*或其任何元素。
Customattributescannotbeappliedtoadelegate*oranyofitselements.
delegate*參數不可標記為paramsAdelegate*parametercannotbemarkedasparams
delegate*類型具有一般指標類型的所有限制。
Adelegate*typehasalloftherestrictionsofanormalpointertype.
指標算術無法直接在函式指標類型上執行。
Pointerarithmeticcannotbeperformeddirectlyonfunctionpointertypes.
函數指標語法Functionpointersyntax
完整函式指標語法是以下列文法表示:Thefullfunctionpointersyntaxisrepresentedbythefollowinggrammar:
pointer_type
:...
|funcptr_type
;
funcptr_type
:'delegate''*'calling_convention_specifier?''
;
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'
|'refreadonly'
;
如果未calling_convention_specifier提供,則預設值為managed。
Ifnocalling_convention_specifierisprovided,thedefaultismanaged.的精確中繼資料編碼calling_convention_specifier和identifier中有效的,unmanaged_calling_convention會包含在呼叫慣例的中繼資料標記法中。
Theprecisemetadataencodingofthecalling_convention_specifierandwhatidentifiersarevalidintheunmanaged_calling_conventioniscoveredinMetadataRepresentationofCallingConventions.
delegateintFunc1(strings);
delegateFunc1Func2(Func1f);
//Functionpointerequivalentwithoutcallingconvention
delegate*
F0andF1havethesamenumberofparameters,andeachparameterD0ninF0hasthesameref,out,orinmodifiersasthecorrespondingparameterD1ninF1.
針對每個值參數(沒有ref、或修飾詞的參數outin)、識別轉換、隱含參考轉換或隱含指標轉換,都是從的參數類型F0到中的對應參數類型F1。
Foreachvalueparameter(aparameterwithnoref,out,orinmodifier),anidentityconversion,implicitreferenceconversion,orimplicitpointerconversionexistsfromtheparametertypeinF0tothecorrespondingparametertypeinF1.
針對每個ref、out或in參數,中的參數類型與F0中的對應參數型別相同F1。
Foreachref,out,orinparameter,theparametertypeinF0isthesameasthecorrespondingparametertypeinF1.
如果傳回型別是以value(no或),則會將傳回型別中的傳回型別refrefreadonly(identity、隱含參考或隱含指標轉換)存在於的傳回型別F1F0。
Ifthereturntypeisbyvalue(noreforrefreadonly),anidentity,implicitreference,orimplicitpointerconversionexistsfromthereturntypeofF1tothereturntypeofF0.
如果傳回型別是傳址(或),的傳回型別和修飾詞就會與的傳回型別和修飾詞refrefreadonlyrefF1相同refF0。
Ifthereturntypeisbyreference(reforrefreadonly),thereturntypeandrefmodifiersofF1arethesameasthereturntypeandrefmodifiersofF0.
的呼叫慣例與F0的呼叫慣例相同F1。
ThecallingconventionofF0isthesameasthecallingconventionofF1.
允許目標方法的位址Allowaddress-oftotargetmethods
現在可將方法群組作為位址運算式的引數。
Methodgroupswillnowbeallowedasargumentstoanaddress-ofexpression.這類運算式的類型會是具有對delegate*等的目標方法簽章和managed呼叫慣例的:Thetypeofsuchanexpressionwillbeadelegate*whichhastheequivalentsignatureofthetargetmethodandamanagedcallingconvention:
unsafeclassUtil{
publicstaticvoidLog(){}
voidUse(){
delegate*
MandFhavethesamenumberofparameters,andeachparameterinMhasthesameref,out,orinmodifiersasthecorrespondingparameterinF.
針對每個值參數(沒有ref、或修飾詞的參數outin)、識別轉換、隱含參考轉換或隱含指標轉換,都是從的參數類型M到中的對應參數類型F。
Foreachvalueparameter(aparameterwithnoref,out,orinmodifier),anidentityconversion,implicitreferenceconversion,orimplicitpointerconversionexistsfromtheparametertypeinMtothecorrespondingparametertypeinF.
針對每個ref、out或in參數,中的參數類型與M中的對應參數型別相同F。
Foreachref,out,orinparameter,theparametertypeinMisthesameasthecorrespondingparametertypeinF.
如果傳回型別是以value(no或),則會將傳回型別中的傳回型別refrefreadonly(identity、隱含參考或隱含指標轉換)存在於的傳回型別FM。
Ifthereturntypeisbyvalue(noreforrefreadonly),anidentity,implicitreference,orimplicitpointerconversionexistsfromthereturntypeofFtothereturntypeofM.
如果傳回型別是傳址(或),的傳回型別和修飾詞就會與的傳回型別和修飾詞refrefreadonlyrefF相同refM。
Ifthereturntypeisbyreference(reforrefreadonly),thereturntypeandrefmodifiersofFarethesameasthereturntypeandrefmodifiersofM.
的呼叫慣例與M的呼叫慣例相同F。
ThecallingconventionofMisthesameasthecallingconventionofF.這包括呼叫慣例位,以及未受管理識別碼中指定的任何呼叫慣例旗標。
Thisincludesboththecallingconventionbit,aswellasanycallingconventionflagsspecifiedintheunmanagedidentifier.
M是一種靜態方法。
Misastaticmethod.
在unsafe內容中,EF如果E包含至少一個適用于其一般形式的方法,且其中至少包含一個方法,且該方法的一般形式適用于使用的參數類型和修飾詞所建立的引數清單(如下所F述),則會從位址的運算式中,將目標設為相容的函式指標類型的隱含轉換存在。
Inanunsafecontext,animplicitconversionexistsfromanaddress-ofexpressionwhosetargetisamethodgroupEtoacompatiblefunctionpointertypeFifEcontainsatleastonemethodthatisapplicableinitsnormalformtoanargumentlistconstructedbyuseoftheparametertypesandmodifiersofF,asdescribedinthefollowing.
選取單一方法,M對應至表單的方法調用E(A),並進行下列修改:AsinglemethodMisselectedcorrespondingtoamethodinvocationoftheformE(A)withthefollowingmodifications:
引數清單A是運算式的清單,每個都分類為變數,且具有的型別和修飾詞(ref、out或in)的對應funcptr_參數_清單F。
TheargumentslistAisalistofexpressions,eachclassifiedasavariableandwiththetypeandmodifier(ref,out,orin)ofthecorrespondingfuncptr_parameter_listofF.
候選方法只是適用于其一般格式的方法,而不是它們的擴充形式適用的方法。
Thecandidatemethodsareonlythosemethodsthatareapplicableintheirnormalform,notthoseapplicableintheirexpandedform.
候選方法只是靜態方法。
Thecandidatemethodsareonlythosemethodsthatarestatic.
如果多載解析演算法產生錯誤,則會發生編譯階段錯誤。
Ifthealgorithmofoverloadresolutionproducesanerror,thenacompile-timeerroroccurs.否則,此演算法M會產生與相同參數數目相同的單一最佳方法,F且會將轉換視為存在。
Otherwise,thealgorithmproducesasinglebestmethodMhavingthesamenumberofparametersasFandtheconversionisconsideredtoexist.
選取的方法M必須相容(如上面所定義的函式指標類型)F。
TheselectedmethodMmustbecompatible(asdefinedabove)withthefunctionpointertypeF.否則,會發生編譯時期錯誤。
Otherwise,acompile-timeerroroccurs.
轉換的結果是類型的函式指標F。
TheresultoftheconversionisafunctionpointeroftypeF.
這表示開發人員可以依賴多載解析規則來搭配使用address運算子:Thismeansdeveloperscandependonoverloadresolutionrulestoworkinconjunctionwiththeaddress-ofoperator:
unsafeclassUtil{
publicstaticvoidLog(){}
publicstaticvoidLog(stringp1){}
publicstaticvoidLog(inti){};
voidUse(){
delegate*
Theaddress-ofoperatorwillbeimplementedusingtheldftninstruction.
這項功能的限制:Restrictionsofthisfeature:
只適用于標示為的方法static。
Onlyappliestomethodsmarkedasstatic.
static不能在中使用非區域函數&。
Non-staticlocalfunctionscannotbeusedin&.這些方法的執行詳細資料不是由語言所指定。
Theimplementationdetailsofthesemethodsaredeliberatelynotspecifiedbythelanguage.這包括它們是否為靜態與實例,或是確切地發出的簽章。
Thisincludeswhethertheyarestaticvs.instanceorexactlywhatsignaturetheyareemittedwith.
函數指標類型上的運算子OperatorsonFunctionPointerTypes
在運算子的unsafe程式碼中,區段的修改方式如下:Thesectioninunsafecodeonoperatorsismodifiedassuch:
在unsafe內容中,有數個可在所有不_funcptrtype_s的_pointertype_s上操作的結構__:Inanunsafecontext,severalconstructsareavailableforoperatingonall_pointer_type_sthatarenot_funcptr_type_s:
*運算子可用來執行指標間接)(指標間接取值。
The*operatormaybeusedtoperformpointerindirection(Pointerindirection).
->運算子可用來透過指標(指標成員存取)來存取結構的成員。
The->operatormaybeusedtoaccessamemberofastructthroughapointer(Pointermemberaccess).
[]運算子可用來編制指標(指標專案存取)的索引。
The[]operatormaybeusedtoindexapointer(Pointerelementaccess).
您&可以使用運算子來取得變數位址,()的operator運算子。
The&operatormaybeusedtoobtaintheaddressofavariable(Theaddress-ofoperator).
++和--運算子可用來遞增和遞減指標(指標遞增和遞減)。
The++and--operatorsmaybeusedtoincrementanddecrementpointers(Pointerincrementanddecrement).
+和-運算子可用來執行指標算術(指標算術)。
The+and-operatorsmaybeusedtoperformpointerarithmetic(Pointerarithmetic).
、、、、==!=<><=和運算子可用=>來比較指標比較)(指標。
The==,!=,,<=,and=>operatorsmaybeusedtocomparepointers(Pointercomparison).
stackalloc運算子可用來從呼叫堆疊(固定大小緩衝區)配置記憶體。
Thestackallocoperatormaybeusedtoallocatememoryfromthecallstack(Fixedsizebuffers).
fixed語句可用來暫時修正變數,以便(fixed語句)取得其位址。
Thefixedstatementmaybeusedtotemporarilyfixavariablesoitsaddresscanbeobtained(Thefixedstatement).
在unsafe內容中,有數個可在所有_funcptrtype_s上運作的結構_:Inanunsafecontext,severalconstructsareavailableforoperatingonall_funcptr_type_s:
&操作員可以用來取得靜態方法的位址(允許目標方法的位址)The&operatormaybeusedtoobtaintheaddressofstaticmethods(Allowaddress-oftotargetmethods)
、、、、==!=<><=和運算子可用=>來比較指標比較)(指標。
The==,!=,,<=,and=>operatorsmaybeusedtocomparepointers(Pointercomparison).
此外,我們會將中的所有區段修改Pointersinexpressions為禁止函式指標類型,除了Pointercomparison和之外Thesizeofoperator。
Additionally,wemodifyallthesectionsinPointersinexpressionstoforbidfunctionpointertypes,exceptPointercomparisonandThesizeofoperator.
更好的函式成員Betterfunctionmember
更好的函式成員規格將會變更,以包含下列程式程式碼:Thebetterfunctionmemberspecificationwillbechangedtoincludethefollowingline:
delegate*比起更明確void*Adelegate*ismorespecificthanvoid*
這表示可以在和上多載,void*delegate*而且仍sensibly使用address運算子。
Thismeansthatitispossibletooverloadonvoid*andadelegate*andstillsensiblyusetheaddress-ofoperator.
類型推斷TypeInference
在unsafe程式碼中,類型推斷演算法會進行下列變更:Inunsafecode,thefollowingchangesaremadetothetypeinferencealgorithms:
輸入類型Inputtypes
https://github.com/dotnet/csharplang/blob/master/spec/expressions.md#input-types
新增下列內容:Thefollowingisadded:
如果E是位址方法群組,且為函式T指標類型,則的所有參數類型T都是具有類型的輸入類型ET。
IfEisanaddress-ofmethodgroupandTisafunctionpointertypethenalltheparametertypesofTareinputtypesofEwithtypeT.
輸出類型Outputtypes
https://github.com/dotnet/csharplang/blob/master/spec/expressions.md#output-types
新增下列內容:Thefollowingisadded:
如果E是傳址方法群組,且為函式指標類型,則的傳回T型別T會是類型為的輸出類型ET。
IfEisanaddress-ofmethodgroupandTisafunctionpointertypethenthereturntypeofTisanoutputtypeofEwithtypeT.
輸出類型推斷Outputtypeinferences
https://github.com/dotnet/csharplang/blob/master/spec/expressions.md#output-type-inferences
專案符號2和3之間會加入下列專案符號:Thefollowingbulletisaddedbetweenbullets2and3:
如果E是傳址方法群組,且T是具有參數型別和傳回型別的函式指標型別T1...TkTb,而且具有類型的多載解析(E具有類型T1..Tk)會產生具有傳回類型的單一方法U,則會從進行下限推斷UTb。
IfEisanaddress-ofmethodgroupandTisafunctionpointertypewithparametertypesT1...TkandreturntypeTb,andoverloadresolutionofEwiththetypesT1..TkyieldsasinglemethodwithreturntypeU,thenalower-boundinferenceismadefromUtoTb.
確切推斷Exactinferences
https://github.com/dotnet/csharplang/blob/master/spec/expressions.md#exact-inferences
下列子專案符號會以案例的形式新增至專案符號2:Thefollowingsub-bulletisaddedasacasetobullet2:
V是函式指標型delegate*
Visafunctionpointertypedelegate*
Visafunctionpointertypedelegate*
Ifthereturnisbyvalue,thenalower-boundinferenceismade.
如果傳回以傳址方式傳回,則會進行完全推斷。
Ifthereturnisbyreference,thenanexactinferenceismade.
如果V2.。
。
VkIfV2..Vk:
如果參數是以傳值方式進行,則會進行上限的推斷。
Iftheparameterisbyvalue,thenanupper-boundinferenceismade.
如果參數是以傳址方式進行,則會進行完全推斷。
Iftheparameterisbyreference,thenanexactinferenceismade.
上限推斷Upper-boundinferences
https://github.com/dotnet/csharplang/blob/master/spec/expressions.md#upper-bound-inferences
下列案例會新增至專案符號2:Thefollowingcaseisaddedtobullet2:
U是函式指標型別delegate*
Uisafunctionpointertypedelegate*
Ifthereturnisbyvalue,thenanupper-boundinferenceismade.
如果傳回以傳址方式傳回,則會進行完全推斷。
Ifthereturnisbyreference,thenanexactinferenceismade.
若為U2.。
。
英國:IfU2..Uk:
如果參數是以傳值方式進行,則會進行下限推斷。
Iftheparameterisbyvalue,thenalower-boundinferenceismade.
如果參數是以傳址方式進行,則會進行完全推斷。
Iftheparameterisbyreference,thenanexactinferenceismade.
in、out和refreadonly參數和傳回類型的中繼資料標記法Metadatarepresentationofin,out,andrefreadonlyparametersandreturntypes
函式指標特徵標記沒有任何參數旗標位置,因此我們必須使用modreqs來編碼參數和傳回類型是in、out或refreadonly。
Functionpointersignatureshavenoparameterflagslocation,sowemustencodewhetherparametersandthereturntypearein,out,orrefreadonlybyusingmodreqs.
in
我們重複使用System.Runtime.InteropServices.InAttribute,並modreq在參數或傳回類型上套用為ref規範,以表示下列各項:WereuseSystem.Runtime.InteropServices.InAttribute,appliedasamodreqtotherefspecifieronaparameterorreturntype,tomeanthefollowing:
如果套用至參數ref規範,則會將這個參數視為in。
Ifappliedtoaparameterrefspecifier,thisparameteristreatedasin.
如果套用至傳回型別ref規範,則會將傳回類型視為refreadonly。
Ifappliedtothereturntyperefspecifier,thereturntypeistreatedasrefreadonly.
out
我們System.Runtime.InteropServices.OutAttribute會使用,modreq在參數類型上套用做為ref規範的,以表示參數為參數out。
WeuseSystem.Runtime.InteropServices.OutAttribute,appliedasamodreqtotherefspecifieronaparametertype,tomeanthattheparameterisanoutparameter.
ErrorsErrors
將modreq套用至傳回型別時,會發生錯誤OutAttribute。
ItisanerrortoapplyOutAttributeasamodreqtoareturntype.
將InAttribute和OutAttribute作為modreq套用至參數類型時,會發生錯誤。
ItisanerrortoapplybothInAttributeandOutAttributeasamodreqtoaparametertype.
如果透過modopt指定任一項,則會忽略它們。
Ifeitherarespecifiedviamodopt,theyareignored.
呼叫慣例的中繼資料標記法MetadataRepresentationofCallingConventions
呼叫慣例會在簽章的方法簽章中,以簽章CallKind中的旗標和零或多個s的組合來編碼modopt。
CallingconventionsareencodedinamethodsignatureinmetadatabyacombinationoftheCallKindflaginthesignatureandzeroormoremodoptsatthestartofthesignature.ECMA-335目前宣告旗標中的下列元素CallKind:ECMA-335currentlydeclaresthefollowingelementsintheCallKindflag:
CallKind
:default
|unmanagedcdecl
|unmanagedfastcall
|unmanagedthiscall
|unmanagedstdcall
|varargs
;
在這些情況下,c#中的函式指標將支援所有但varargs。
Ofthese,functionpointersinC#willsupportallbutvarargs.
此外,執行時間(和最後335)將會更新,以CallKind在新的平臺上包含新的。
Inaddition,theruntime(andeventually335)willbeupdatedtoincludeanewCallKindonnewplatforms.這並不是目前的正式名稱,但這份檔將用unmanagedext來做為新的可延伸呼叫慣例格式的替代預留位置。
Thisdoesnothaveaformalnamecurrently,butthisdocumentwilluseunmanagedextasaplaceholdertostandforthenewextensiblecallingconventionformat.如果沒有modopt,unmanagedext則為平臺預設呼叫慣例,unmanaged沒有方括弧。
Withnomodopts,unmanagedextistheplatformdefaultcallingconvention,unmanagedwithoutthesquarebrackets.
將對應calling_convention_specifier至CallKindMappingthecalling_convention_specifiertoaCallKind
如果calling_convention_specifier省略,或指定為,會managed對應至defaultCallKind。
Acalling_convention_specifierthatisomitted,orspecifiedasmanaged,mapstothedefaultCallKind.這是CallKind未使用屬性之任何方法的預設值UnmanagedCallersOnly。
ThisisdefaultCallKindofanymethodnotattributedwithUnmanagedCallersOnly.
C#會辨識出從ECMA335對應至特定現有非受控的4個特殊識別碼CallKind。
C#recognizes4specialidentifiersthatmaptospecificexistingunmanagedCallKindsfromECMA335.為了進行這項對應,必須自行指定這些識別碼(沒有其他識別碼),而這項需求會編碼為的規格unmanaged_calling_convention。
Inorderforthismappingtooccur,theseidentifiersmustbespecifiedontheirown,withnootheridentifiers,andthisrequirementisencodedintothespecforunmanaged_calling_conventions.這些識別碼CdeclThiscallStdcallFastcall分別對應至、、和,分別對應unmanagedcdecl至unmanagedthiscallunmanagedstdcallunmanagedfastcall、、和。
TheseidentifiersareCdecl,Thiscall,Stdcall,andFastcall,whichcorrespondtounmanagedcdecl,unmanagedthiscall,unmanagedstdcall,andunmanagedfastcall,respectively.如果指定了一個以上的identifer,或單一不identifier是特別辨識的識別碼,我們就會在識別碼上執行特殊名稱查閱,並具有下列規則:Ifmorethanoneidentiferisspecified,orthesingleidentifierisnotofthespeciallyrecognizedidentifiers,weperformspecialnamelookupontheidentifierwiththefollowingrules:
我們在前面identifier加上字串CallConvWeprependtheidentifierwiththestringCallConv
我們只會查看命名空間中定義的類型System.Runtime.CompilerServices。
WelookonlyattypesdefinedintheSystem.Runtime.CompilerServicesnamespace.
我們只會查看應用程式核心程式庫中定義的類型,也就是定義且沒有相依性的程式庫System.Object。
Welookonlyattypesdefinedinthecorelibraryoftheapplication,whichisthelibrarythatdefinesSystem.Objectandhasnodependencies.
我們只探討公用類型。
Welookonlyatpublictypes.
如果查閱在中指定的所有identifier,則會將unmanaged_calling_conventionCallKind設定為,並針對函式指標簽章開頭的unmanagedext集合中的每個已解析類型進行編碼modopt。
Iflookupsucceedsonalloftheidentifiersspecifiedinanunmanaged_calling_convention,weencodetheCallKindasunmanagedext,andencodeeachoftheresolvedtypesinthesetofmodoptsatthebeginningofthefunctionpointersignature.要注意的是,這些規則表示使用者不能在這些中加上前置詞identifierCallConv,因為這樣會導致查詢CallConvCallConvVectorCall。
Asanote,theserulesmeanthatuserscannotprefixtheseidentifierswithCallConv,asthatwillresultinlookingupCallConvCallConvVectorCall.
在解讀中繼資料時,我們先看看CallKind。
Wheninterpretingmetadata,wefirstlookattheCallKind.如果不是unmanagedext,我們會忽略傳回型別上的所有,modopt以判斷呼叫慣例,並只使用CallKind。
Ifitisanythingotherthanunmanagedext,weignoreallmodoptsonthereturntypeforthepurposesofdeterminingthecallingconvention,anduseonlytheCallKind.如果CallKind是,我們會在函式unmanagedext指標類型的開頭查看modopts,並採用符合下列需求的所有類型聯集:IftheCallKindisunmanagedext,welookatthemodoptsatthestartofthefunctionpointertype,takingtheunionofalltypesthatmeetthefollowingrequirements:
是在核心程式庫中定義,也就是參考沒有其他程式庫和定義的程式庫System.Object。
Theisdefinedinthecorelibrary,whichisthelibrarythatreferencesnootherlibrariesanddefinesSystem.Object.
此類型定義于System.Runtime.CompilerServices命名空間中。
ThetypeisdefinedintheSystem.Runtime.CompilerServicesnamespace.
型別開頭為前置詞CallConv。
ThetypestartswiththeprefixCallConv.
此類型為public。
Thetypeispublic.
這些代表在identifierunmanaged_calling_convention定義來源中的函式指標類型時,在中的上執行查閱時必須找到的類型。
Theserepresentthetypesthatmustbefoundwhenperforminglookupontheidentifiersinanunmanaged_calling_conventionwhendefiningafunctionpointertypeinsource.
CallKindunmanagedext如果目標執行時間不支援此功能,嘗試搭配使用函式指標時,就會發生錯誤。
ItisanerrortoattempttouseafunctionpointerwithaCallKindofunmanagedextifthetargetruntimedoesnotsupportthefeature.這會藉由尋找常數的存在而決定System.Runtime.CompilerServices.RuntimeFeature.UnmanagedCallKind。
ThiswillbedeterminedbylookingforthepresenceoftheSystem.Runtime.CompilerServices.RuntimeFeature.UnmanagedCallKindconstant.如果這個常數存在,則會將執行時間視為支援此功能。
Ifthisconstantispresent,theruntimeisconsideredtosupportthefeature.
System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute
System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute是CLR所使用的屬性,表示應該使用特定的呼叫慣例來呼叫方法。
System.Runtime.InteropServices.UnmanagedCallersOnlyAttributeisanattributeusedbytheCLRtoindicatethatamethodshouldbecalledwithaspecificcallingconvention.基於這個原因,我們會介紹下列支援以使用屬性:Becauseofthis,weintroducethefollowingsupportforworkingwiththeattribute:
直接從c#呼叫以這個屬性批註的方法是錯誤的。
ItisanerrortodirectlycallamethodannotatedwiththisattributefromC#.使用者必須取得方法的函式指標,然後叫用該指標。
Usersmustobtainafunctionpointertothemethodandtheninvokethatpointer.
將屬性套用至一般靜態方法或一般靜態區域函式以外的任何元素時,會發生錯誤。
Itisanerrortoapplytheattributetoanythingotherthananordinarystaticmethodorordinarystaticlocalfunction.
C#編譯器會標示從中繼資料匯入的任何非靜態或靜態非一般方法,此屬性是語言不支援的。
TheC#compilerwillmarkanynon-staticorstaticnon-ordinarymethodsimportedfrommetadatawiththisattributeasunsupportedbythelanguage.
以屬性標記的方法,具有不是的參數或傳回型別時,會發生錯誤unmanaged_type。
Itisanerrorforamethodmarkedwiththeattributetohaveaparameterorreturntypethatisnotanunmanaged_type.
標記有屬性的方法會有型別參數,即使這些型別參數受限於,也是錯誤unmanaged。
Itisanerrorforamethodmarkedwiththeattributetohavetypeparameters,evenifthosetypeparametersareconstrainedtounmanaged.
泛型型別中的方法會以屬性標記,是一項錯誤。
Itisanerrorforamethodinagenerictypetobemarkedwiththeattribute.
將以屬性標記的方法轉換為委派類型時,會發生錯誤。
Itisanerrortoconvertamethodmarkedwiththeattributetoadelegatetype.
針對UnmanagedCallersOnly.CallConvs不符合modopt在中繼資料中呼叫慣例的需求所指定的任何類型時,會發生錯誤。
ItisanerrortospecifyanytypesforUnmanagedCallersOnly.CallConvsthatdonotmeettherequirementsforcallingconventionmodoptsinmetadata.
當您決定以有效屬性標記之方法的呼叫慣例時UnmanagedCallersOnly,編譯器會對屬性中指定的型別執行下列檢查,CallConvs以判斷CallKindmodopt應該用來判斷呼叫慣例的有效和。
WhendeterminingthecallingconventionofamethodmarkedwithavalidUnmanagedCallersOnlyattribute,thecompilerperformsthefollowingchecksonthetypesspecifiedintheCallConvspropertytodeterminetheeffectiveCallKindandmodoptsthatshouldbeusedtodeterminethecallingconvention:
如果未指定任何類型,則CallKind會將視為,在函式unmanagedextmodopt指標類型的開頭沒有呼叫慣例s。
Ifnotypesarespecified,theCallKindistreatedasunmanagedext,withnocallingconventionmodoptsatthestartofthefunctionpointertype.
如果指定了一種類型,而且該類型命名為CallConvCdecl、CallConvThiscall、CallConvStdcall或CallConvFastcall,則CallKind會分別將視為、、或。
在函式unmanagedcdeclunmanagedthiscallunmanagedstdcallunmanagedfastcallmodopt指標類型的開頭沒有呼叫慣例s。
Ifthereisonetypespecified,andthattypeisnamedCallConvCdecl,CallConvThiscall,CallConvStdcall,orCallConvFastcall,theCallKindistreatedasunmanagedcdecl,unmanagedthiscall,unmanagedstdcall,orunmanagedfastcall,respectively,withnocallingconventionmodoptsatthestartofthefunctionpointertype.
如果指定了多個型別,或單一型別未命名上述的其中一個特別呼叫的out型別,則CallKind會將視為,並在函式unmanagedext指標型別開頭將所指定類型的聯集視為modopts。
Ifmultipletypesarespecifiedorthesingletypeisnotnamedoneofthespeciallycalledouttypesabove,theCallKindistreatedasunmanagedext,withtheunionofthetypesspecifiedtreatedasmodoptsatthestartofthefunctionpointertype.
編譯器接著會查看此有效CallKind和modopt集合,並使用標準中繼資料規則來判斷函式指標類型的最終呼叫慣例。
ThecompilerthenlooksatthiseffectiveCallKindandmodoptcollectionandusesnormalmetadatarulestodeterminethefinalcallingconventionofthefunctionpointertype.
未結問題OpenQuestions
偵測執行時間支援unmanagedextDetectingruntimesupportforunmanagedext
https://github.com/dotnet/runtime/issues/38135追蹤新增此旗標。
https://github.com/dotnet/runtime/issues/38135tracksaddingthisflag.根據評論的意見反應,我們將使用問題中所指定的屬性,或使用出現的UnmanagedCallersOnlyAttribute作為旗標,判斷執行時間是否支援unmanagedext。
Dependingonthefeedbackfromreview,wewilleitherusethepropertyspecifiedintheissue,orusethepresenceofUnmanagedCallersOnlyAttributeastheflagthatdetermineswhethertheruntimessupportsunmanagedext.
考量Considerations
允許實例方法Allowinstancemethods
您可以利用EXPLICITTHISinstancec#程式碼)中所命名的CLI呼叫慣例(,擴充提案以支援實例方法。
TheproposalcouldbeextendedtosupportinstancemethodsbytakingadvantageoftheEXPLICITTHISCLIcallingconvention(namedinstanceinC#code).這種形式的CLI函式指標會將this參數放置為函式指標語法的明確第一個參數。
ThisformofCLIfunctionpointersputsthethisparameterasanexplicitfirstparameterofthefunctionpointersyntax.
unsafeclassInstance{
voidUse(){
delegate*instance
Thisissoundbutaddssomecomplicationtotheproposal.尤其是因為instancemanaged這兩個案例都是用來叫用具有相同c#簽章的managed方法,所以與呼叫慣例不同的函式指標也會不相容。
ParticularlybecausefunctionpointerswhichdifferedbythecallingconventioninstanceandmanagedwouldbeincompatibleeventhoughbothcasesareusedtoinvokemanagedmethodswiththesameC#signature.此外,在每個案例中,如果有一個簡單的因應措施,請考慮使用static區域函數。
Alsoineverycaseconsideredwherethiswouldbevaluabletohavetherewasasimpleworkaround:useastaticlocalfunction.
unsafeclassInstance{
voidUse(){
staticstringtoString(Instancei)=>i.ToString();
delegate*
Insteadofrequiringunsafeateveryuseofadelegate*,onlyrequireitatthepointwhereamethodgroupisconvertedtoadelegate*.這就是核心安全問題的播放(知道,當值)時,無法卸載包含的元件。
Thisiswherethecoresafetyissuescomeintoplay(knowingthatthecontainingassemblycannotbeunloadedwhilethevalueisalive).unsafe在其他位置上的要求可能會被視為過度。
Requiringunsafeontheotherlocationscanbeseenasexcessive.
這是設計原本的用途。
Thisishowthedesignwasoriginallyintended.但產生的語言規則覺得很麻煩。
Buttheresultinglanguagerulesfeltveryawkward.您無法隱藏這是指標值的事實,而且即使沒有關鍵詞,也不會繼續查看unsafe。
It'simpossibletohidethefactthatthisisapointervalueanditkeptpeekingthroughevenwithouttheunsafekeyword.例如,object無法允許轉換,它不能是的成員class等等。
C#設計是要求unsafe所有指標用途,因此這種設計會如下所示。
Forexampletheconversiontoobjectcan'tbeallowed,itcan'tbeamemberofaclass,etc...TheC#designistorequireunsafeforallpointerusesandhencethisdesignfollowsthat.
開發人員還是能夠在值的最上層呈現安全的包裝函式delegate*,就像是現今一般指標類型一樣。
Developerswillstillbecapableofpresentingasafewrapperontopofdelegate*valuesthesamewaythattheydofornormalpointertypestoday.考量:Consider:
unsafestructAction{
delegate*
延伸文章資訊
- 1Function pointer - Wikipedia
A function pointer, also called a subroutine pointer or procedure pointer, is a pointer that poin...
- 2Difference between function pointers and pointer to function - CodeProject
- 3Function Pointer in C - GeeksforGeeks
1) Unlike normal pointers, a function pointer points to code, not data. Typically a function poin...
- 4C Language Pointer as Function Argument - Studytonight
- 5Function Pointer in C - Tutorialspoint