2011-03-31 21 views
9

C# 4.0'deki "isteğe bağlı parametreler" özelliğini çok ilginç buldum, bu yüzden nasıl yapıldığını anlamaya çalıştım. yüzden böyle bir yöntem yazdı: o zaman,MSIL'de [opt] ne anlama geliyor?

private static void A(int a = 5) { } 

bunu Derleyen IL DASM bunu bozulamaz, bu IL kod şudur:

.method private hidebysig static void A([opt] int32 a) cil managed 
{ 
    .param [1] = int32(0x00000005) 
    // Code size  2 (0x2) 
    .maxstack 8 
    IL_0000: nop 
    IL_0001: ret 
} // end of method Program::A 

Ve onun metaverilerde bu var:

(1) ParamToken: (08000002) Adı: bir bayraklar: [İsteğe bağlı] [HasDefault] (00001010) Varsayılan: (I4) 5

Yani ipucunu takip etti ve böyle bir yöntemi yazdı:

private static void B([Optional, DefaultParameterValue(78)]int b) { } 

derlenmiş ve dönüştürülemez, ve C# derleyicisi (adı hariç), yöntem A ve B için hemen hemen aynı msil üretilen kod bulundu.

orada IL kodunda özelliklerin hiçbir iz ve bu yanlış geldi, bu yüzden böyle özel bir özellik yazdı görebileceğiniz gibi: Sonra

[AttributeUsage(AttributeTargets.Parameter)] 
public class MyTestAttribute : Attribute 
{ 
} 

böyle bir yöntem C kullandı:

private static void C([MyTest]int c) { } 

bunu Derleyen ve sonra decompiled onu ve hah, bunu buldum:

.method private hidebysig static void C(int32 c) cil managed 
{ 
    .param [1] 
    .custom instance void ConsoleApplication1.MyTestAttribute::.ctor() = (01 00 00 00) 
    // Code size  2 (0x2) 
    .maxstack 8 
    IL_0000: nop 
    IL_0001: ret 
} // end of method Program::C 

ikinci satırı yöntem gövdesi, özel özniteliğimin ctor çağırır.

Yani bu benim şüpheleri yol açar:

  1. [opt] ne anlama gelir? A ve B parametresinin önünde görünen kelimeyi kastediyorum.
  2. Yöntem C, parametresine uygulanan Attribute öğesinin yapıcısını ve A ve B yöntemini nasıl çağırmaz?
  3. Meta verilerde herhangi bir DefaultParameterValueAttribute belirtisi göremiyorum, ancak OptionalAttribute ve MyTestAttribute öğelerini bulabilirim. Neden? Kaybettiğim bir şey var mı?

Şimdiden teşekkürler.

cevap

10

Param meta veri tablosu zaten Flags sütunu aracılığıyla isteğe bağlı ve varsayılan değerleri açıklayabildiğinden C# derleyicisinin öznitelikleri göndermesi gerekmez. 23.1.13 itibaren

ECMA 335 içinde: (| 0x1000 0x0010)

Flag   Value Description 
----------------------------------------------------- 
In    0x0001 Parameter is [In] 
Out    0x0002 Parameter is [Out] 
Optional  0x0010 Parameter is optional 
HasDefault  0x1000 Parameter has a default value 
HasFieldMarshal 0x2000 Parameter has FieldMarshal 

bir parametre isteğe bağlıdır belirtir ve varsayılan değeri olan bir bayrak değere sahip olabilir. Varsayılan değere sahip olan parametreler, Sabit meta veri tablosunda ilişkili bir simgeye sahip olacaktır.

Sabit meta veri tablosu, söz konusu Param jetonu olan Parent sütununa ve varsayılan değerin saklandığı blob yığınına bir dizin olacak bir Value sütununa sahiptir.

Yani sorularınızı yanıtlamak için:

  1. [opt] Opsiyonel bayrak kümesi vardır Param simgesi için Flags sütun anlamına gelir.
  2. Yukarıda belirttiğim gibi, benim tahminim C# derleyicisinin Opsiyonel/DefaultParameterValue öznitelikleri tanıması ve bunları basitçe parametre bayraklarına dönüştürmesidir.
  3. Düzenleme: C# derleyicisi, Optional flag parametresi için kullanılmasına rağmen, OptionalAttribute için kullanılmayan bir TypeRef yayımlıyor görünür. Yine de, DefaultParameterValueAttribute için bir TypeRef yayınlamıyor. Kullanılmayan TypeRefs/MemberRefs yayınlamak için küçük bir derleyici hatası olabilir.
+0

Bu yazının bir kısmı çok yakında yanıt almayı beklemiyordum. Ama seninki gibi görünüyor. – CuiPengFei

+0

Ve ben opt optimated anlamına gelir düşünüyorum ... – CuiPengFei

+0

Vay, bir CSC bir hata bulmak için beklemiyorduk. – CuiPengFei

2

2/3; derleyicinin gerçekten öznitelik değil, IL metadatası olarak yorumladığı birkaç özellik vardır; Burada durum böyle görünüyor; [Serializable] başka bir örnektir. Varsayılan ilişkin veriler olduğunda: Default: (I4) 5 - değil kodundaki tüm özellikler meta verileri (yine burada [Serializable] bakıyorum) [Serializable] (yorumlar) o noktadan yeniden


yılında nitelikleri olur;

[Description("abc")] 
class Foo { } 

[Serializable] 
class Bar { } 

hangi çekirdek IL geçerli:: işte size bir örnek Foo yılında

.class private auto ansi beforefieldinit Foo 
    extends [mscorlib]System.Object 
{ 
    .custom instance void [System]System.ComponentModel.DescriptionAttribute::.ctor(string) = { string('abc') } 
    .method public hidebysig specialname rtspecialname instance void .ctor() cil managed 
    { 
    } 

} 
.class private auto ansi serializable beforefieldinit Bar 
    extends [mscorlib]System.Object 
{ 
    .method public hidebysig specialname rtspecialname instance void .ctor() cil managed 
    { 
    } 

} 

(bazı keyfi özellik için), elde ederiz:

.custom instance void [System]System.ComponentModel.DescriptionAttribute::.ctor(string) = { string('abc') } 

Ancak bunun için geçerli değildir [Serializable]; bunun yerine, bu tür:

+1

Teşekkürler, bu çok şey açıklıyor. BTW, "İsteğe bağlı parametreler" ile ilgili yorum yaptığınızda yazınızı gördüm, :) – CuiPengFei

+0

Sadece test ettim, aslında, Serializable metadatanın reftype bölümünde görünmeye devam ediyor. – CuiPengFei

+0

@CuiPengFei - –