2013-05-23 22 views
5

È possibile aggirare la seguente limitazione:Passando matrice statica in attributo

Creare una matrice sola lettura statica in una classe:

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

quindi farla passare come un parametro per un attributo:

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

    FooAttribute() 
    { 
    } 
} 

--- Diciamo Box è una proprietà di classe a ---

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

So che questo non verrà compilato e si tradurrà in questo errore:

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

E 'possibile andare in giro questo in qualche modo essere in grado di utilizzare la matrice statica? Lo chiedo dato che questo sarà molto più conveniente in termini di manutenzione, dal momento che ho molte proprietà.

Grazie in anticipo.

+1

dovrebbe "readonly" essere "const" concettualmente? – David

+1

Forse, ma sono [diversi] (http://msdn.microsoft.com/en-us/library/acdd6hb7 (v = vs.110) .aspx): la parola chiave readonly è diversa dalla parola chiave const. Un campo const può essere inizializzato solo alla dichiarazione del campo. Un campo di sola lettura può essere inizializzato o alla dichiarazione o in un costruttore. Pertanto, i campi di sola lettura possono avere valori diversi a seconda del costruttore utilizzato. –

risposta

4

Purtroppo questo non è possibile. Gli attributi (inclusi i valori dei loro argomenti) sono inseriti nei metadati dell'assieme dal compilatore in modo che debba essere in grado di valutarli in fase di compilazione (da qui la restrizione alle espressioni costanti, l'eccezione per le espressioni di creazione dell'array è stata ovviamente fatta perché altrimenti non si potevano avere argomenti array).

Al contrario, il codice che inizializza effettivamente A.Months viene eseguito solo in fase di esecuzione.

+0

o in altre parole, l'attributo deve essere determinato al momento della compilazione, e le unità di lettura vengono assegnate in fase di runtime? Questa comprensione è corretta? – David

+0

@David: Sì, esattamente. – Jon

+0

@Jon: Grazie –

7

No, in pratica.

Si potrebbe, tuttavia, sottoclasse l'attributo e utilizzare tale, cioè

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

o:

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

e decorare con [AwesomeFoo] invece. Se si utilizza la riflessione per cercare FooAttribute, funzionerà come previsto:

[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 
     } 
    } 
} 

Si potrebbe forse nido questo all'interno A, quindi si sta decorando con:

[A.FooMonths] 

o simile

+0

Aspetta, cosa? Come? Che tipo di compilatore di magia nera è questo? – Jon

+0

Hmmm ... e mi chiedo: cosa succede se rifletti in un contesto di sola riflessione? – Jon

+1

@Jon si, poi sei beccato. I metadati non sanno nulla di ciò che accade all'interno. Se hai solo accesso ai metadati, tutto ciò che sarai in grado di dire è "c'è un AwesomeFooAttribute", che posso dire che è esso stesso un "FooAttribute". La maggior parte delle persone, tuttavia, non lavora in contesti di sola riflessione. Come succede, io * faccio * molto di questo (tramite IKVM.Reflection, di solito) - e sento il tuo dolore :) –

2

Breve risposta: No.

Ma è possibile fare riferimento all'array int con la chiave:

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}