2011-06-17 13 views
13

Piszę atrybut niestandardowy zabezpieczeń i mam dziwne zachowanie kompilatora ... Kiedy używam atrybut w tym samym pliku, domyślne wartości parametrów działa dobrze:Czy to jest opcjonalny parametr błędu kompilatora C# 4.0?

using System.Security.Permissions; 

[System.Serializable] 
sealed class FooAttribute : CodeAccessSecurityAttribute { 
    public FooAttribute(SecurityAction action = SecurityAction.Demand) : base(action) { } 
    public override System.Security.IPermission CreatePermission() { return null; } 
} 

[Foo] class Program { 
    static void Main(string[] args) { } 
} 

Ale kiedy jestem oddzielenie kodu powyżej w dwóch plikach, takich jak to - plik 1:

using System.Security.Permissions; 

[System.Serializable] 
sealed class FooAttribute : CodeAccessSecurityAttribute { 
    public FooAttribute(SecurityAction action = SecurityAction.Demand) : base(action) { } 
    public override System.Security.IPermission CreatePermission() { return null; } 
} 

i plik 2:

[Foo] class Program { 
    static void Main(string[] args) { } 
} 

mam błąd kompilatora:

Error: 'FooAttribute' does not contain a constructor that takes 0 arguments

Dzieje się tak tylko z CodeAccessSecurityAttribute dziedziców, wygląda bardzo dziwnie ...

+2

Jaki jest związek między FooAttribute, w źródle i DebugCallTraceAttribute, w komunikacie o błędzie? –

+2

Czy istnieje przyczyna "SecurityAttribute" w pierwszym fragmencie i "CodeAccessSecurityAttribute" w drugim? Wygląda na to, że powinny być takie same dla ważnego minimalnego przypadku testowego. (Np. Czy jest to związane z tą zmianą, czy jest w dwóch plikach lub obu?) –

+0

przykro, jest 3 nad ranem w Moskwie, wszystkie błędy fragmentu są naprawione – ControlFlow

Odpowiedz

13

Więc nie ma dokładnej odpowiedzi, ale wziąłem go tak daleko, jak mogłem patrząc na niego. Myślę, że rozumiem, dlaczego to się dzieje, kiedy dziedziczą CodeAccessSecurityAttribute i nie SecurityAttribute. Jeśli spojrzeć na IL generowane podczas stosowania atrybutu Foo kiedy dziedziczy CodeAccessSecurityAttribute wygląda to tak:

.permissionset demand = {class 'ConsoleApplication1.FooAttribute, ConsoleApplication1, Version=1.0.0.0, Culture=neutral' = {}} 

Kiedy Foo dziedziczy z SecurityAttribute it wygląda tak:

.custom instance void ConsoleApplication1.FooAttribute::.ctor(valuetype [mscorlib]System.Security.Permissions.SecurityAction) = (01 00 02 00 00 00 00 00) 

Oczywiście wartość CodeAccessSecurityAttribute znacznie zmienia IL wygenerowany przez zastosowanie atrybutu.

Patrząc na IL więcej, jeśli możemy zmienić deklarację Foo być jak następująco

[Foo(SecurityAction.Demand)] 

Otrzymujemy następujące IL:

.permissionset demand = {class 'ConsoleApplication1.FooAttribute, ConsoleApplication1, Version=1.0.0.0, Culture=neutral' = {}} 

jego samego, jak to było, kiedy nie podać opcjonalny parametr. Dodatkowo możemy spowodować błąd nie tylko przez podział atrybut i klasę na oddzielnych plikach Program możemy doprowadzić go przez rozmieszczanie plików w klasie jak poniżej:

[Foo] 
class Program 
{ 

    static void Main(string[] args) {} 


} 

[System.Serializable] 
sealed class FooAttribute : CodeAccessSecurityAttribute 
{ 
    public FooAttribute(SecurityAction action = SecurityAction.Demand) : base(action) { } 
    public override System.Security.IPermission CreatePermission() { return null; } 
} 

Jeszcze bardziej interesujące, jeśli mamy następujące z klasą Other i Other2 podać błąd, ale nie ma Program. Tylko zajęcia, które przychodzą przed Foo w pliku będzie miał błąd

[Foo] 
class Other 
{ 

} 

[Foo] 
class Other2 
{ 
} 

[System.Serializable] 
sealed class FooAttribute : CodeAccessSecurityAttribute 
{ 
     public FooAttribute(SecurityAction action = SecurityAction.Demand) : base(action) { } 
     public override System.Security.IPermission CreatePermission() { return null; }  } 

[Foo] 
class Program 
{ 

    static void Main(string[] args) {} 
} 

Co to mówi mi to, że nie jest to problem gdzieś w procesie budowania. Nie wiem wystarczająco dużo o tym, jak działa Code Access Security, aby określić, jaki jest dokładny problem. Musi być częścią procesu, który analizuje CodeAccessSecurityAttributes i robi coś z próbą zastosowania SecurityAction do kodu. Zakładam, że buduje jakieś metadane dla zespołu. Musi to zrobić w pewien uporządkowany sposób, aby nie widział parametru opcjonalnego, dopóki nie przejdzie już klasy Program. Następnie musi użyć tych metadanych w pewien sposób podczas procesu budowania i tam właśnie widzisz awarię. Aby uzyskać więcej szczegółów, będziemy musieli mieć nadzieję, że ktoś, kto zna kompilator, np. Eric, może rzucić trochę światła na to. Przekazałbym go na connect.microsoft.com jako jeden z sugerowanych komentarzy, ponieważ wygląda na to, że błąd spowodowany jest tym, że rzeczy są przemierzane.

+1

+1 ode mnie za dobrą analizę. – Jehof

+0

Jeśli tylko ** wszystkie ** raporty o błędach były tak dobrze zbadane i napisane! –

Powiązane problemy