2013-05-23 17 views
5

Czy możliwe jest ominięcie następujące ograniczenie:Mijając tablicę statyczną w atrybucie

Tworzenie statycznej readonly tablicę w klasie:

public class A 
{ 
    public static readonly int[] Months = new int[] { 1, 2, 3}; 
} 

Następnie przekazać go jako parametr do atrybutu:

public class FooAttribute : Attribute 
{ 
    public int[] Nums { get; set; } 

    FooAttribute() 
    { 
    } 
} 

--- Powiedzmy Box jest własnością klasy A ---

[Foo(Nums = A.Months)] 
public string Box { get; set; } 

wiem, że to nie będzie kompilować i spowoduje tego błędu:

"An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type".

Czy można to jakoś obejść, aby móc użyć statycznej tablicy? Pytam, ponieważ będzie to znacznie wygodniejsze z punktu widzenia konserwacji, ponieważ mam wiele właściwości.

Z góry dziękuję.

+1

powinien "tylko do odczytu" być konceptualny? – David

+1

Może, ale są [różne] (http://msdn.microsoft.com/en-us/library/acdd6hb7 (v = vs.110) .aspx): Słowo kluczowe readonly różni się od słowa kluczowego const. Pole const można zainicjować tylko na deklaracji pola. Pole tylko do odczytu można zainicjować na deklaracji lub w konstruktorze. Dlatego pola readonly mogą mieć różne wartości w zależności od użytego konstruktora. –

Odpowiedz

4

Niestety nie jest to możliwe. Atrybuty (w tym wartości ich argumentów) są umieszczane w metadanych zestawu przez kompilator, więc musi być w stanie ocenić je w czasie kompilacji (stąd ograniczenie do stałych wyrażeń, wyjątek dla wyrażeń tworzenia tablicy został oczywiście wykonany, ponieważ w przeciwnym razie w ogóle nie mogłeś mieć argumentów tablicowych).

W przeciwieństwie do tego kod, który faktycznie inicjuje A.Months, jest wykonywany tylko w środowisku wykonawczym.

+0

lub innymi słowy, atrybut musi zostać określony podczas kompilacji, a vars tylko do odczytu są przydzielane w czasie wykonywania? Czy to zrozumienie jest poprawne? – David

+0

@David: Tak, dokładnie. – Jon

+0

@Jon: Dziękuję –

7

Nie, zasadniczo.

Można by jednak podklasa atrybut i użyć jej, to znaczy

class AwesomeFooAttribute : FooAttribute { 
    public AwesomeFooAttribute() : FooAttribute(A.Months) {} 
} 

czyli

class AwesomeFooAttribute : FooAttribute { 
    public AwesomeFooAttribute() { 
     Nums = A.Months; 
    } 
} 

i udekorować [AwesomeFoo] zamiast. Jeśli używasz refleksji szukać FooAttribute, to będzie działać zgodnie z oczekiwaniami:

[AwesomeFoo] 
static class Program 
{ 
    static void Main() 
    { 
     var foo = (FooAttribute)Attribute.GetCustomAttribute(
      typeof(Program), typeof(FooAttribute)); 
     if (foo != null) 
     { 
      int[] nums = foo.Nums; // 1,2,3 
     } 
    } 
} 

Mogłabyś może zagnieździć to wewnątrz A, więc są zdobienia z:

[A.FooMonths] 

lub podobny

+0

Czekaj, co? W jaki sposób? Jakiego rodzaju czarną magią jest kompilator? – Jon

+0

Hmmm ... i zastanawiam się: co się dzieje, jeśli zastanowisz się w kontekście refleksyjnym? – Jon

+1

@Ja, tak, jesteś oszołomiony. Metadane nic nie wiedzą o tym, co dzieje się w środku. Jeśli masz dostęp tylko do metadanych, wszystko, co będziesz mógł powiedzieć, to "istnieje" AwesomeFooAttribute ", który sam mogę określić jako" FooAttribute ". Większość ludzi nie działa jednak w kontekście refleksyjnym. Tak się składa, że ​​robię to często (zazwyczaj za pośrednictwem IKVM.Reflection) - i czuję twój ból :) –

2

Krótki odpowiedź: nr

Ale możesz odwołać się do tablicy int klawiszem:

public class A 
{ 
    public static readonly Dictionnary<int, int[]> NumsArrays 
       = new[]{{1, new[]{1,1,1}}, {2, new[]{2,2,2}}, {3, new[]{3,3,3}}}; 
    public const int Num1 = 1; 
    public const int Num2 = 2; 
    public const int Num3 = 3; 
} 

public class FooAttribute : Attribute 
{ 
    public int NumsId { get; set; } 

    FooAttribute() 
    { 
    } 
} 

[Foo(NumsID = A.Num3)] 
public string Box { get; set; } 

//Evaluation: 
int id = (FooAttribute) Attribute.GetCustomAttribute(type, typeof (FooAttribute)); 
int[] result = A.NumsArrays[id];//result is {3,3,3} 
Powiązane problemy