2013-05-23 12 views
5

Ist es möglich, die folgende Einschränkung zu umgehen:in Attribut statisches Array Passing

Erstellen einer statischen Nur-Lese-Array in einer Klasse:

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

Dann geben sie als Parameter ein Attribut:

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

    FooAttribute() 
    { 
    } 
} 

--- sagen wir Box ist eine Eigenschaft der Klasse A ---

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

Ich weiß, dass dies nicht kompilieren und zu diesem Fehler führt:

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

Ist es möglich, um diesen irgendwie gehen zu können, um die statische Array benutzen? Ich frage, da dies viel wartungsfreundlicher sein wird, da ich viele Eigenschaften habe.

Vielen Dank im Voraus.

+1

sollte "readonly" konzeptionell "const" sein? – David

+1

Vielleicht, aber sie sind [anders] (http://msdn.microsoft.com/en-us/library/acdd6hb7 (v = vs.110) .aspx): Das Schlüsselwort readonly unterscheidet sich vom Schlüsselwort const. Ein const-Feld kann nur bei der Deklaration des Feldes initialisiert werden. Ein schreibgeschütztes Feld kann entweder an der Deklaration oder in einem Konstruktor initialisiert werden. Daher können schreibgeschützte Felder abhängig vom verwendeten Konstruktor unterschiedliche Werte haben. –

Antwort

4

Leider ist das nicht möglich. Die Attribute (einschließlich der Werte ihrer Argumente) werden vom Compiler in die Assemblymetadaten geschrieben, so dass sie sie zur Kompilierzeit auswerten können (daher die Beschränkung auf konstante Ausdrücke; die Ausnahme für Array-Erstellungsausdrücke wurde offensichtlich gemacht, weil andernfalls) Sie könnten Array-Argumente überhaupt nicht haben).

Im Gegensatz dazu wird der Code, der A.Months initialisiert, nur zur Laufzeit ausgeführt.

+0

oder mit anderen Worten, Attribut muss zur Kompilierungszeit bestimmt werden, und nur zur Laufzeit werden vars zugewiesen? Ist dieses Verständnis korrekt? – David

+0

@David: Ja, genau. – Jon

+0

@Jon: Danke –

7

Nein, im Grunde genommen.

konnte Sie jedoch Unterklasse das Attribut und verwenden, die, das heißt

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

oder:

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

und dekorieren mit [AwesomeFoo] statt. Wenn Sie Reflektion verwenden für FooAttribute zu suchen, wird es wie erwartet:

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

Sie könnten vielleicht Nest dieses Innere A, so dass Sie die Dekoration mit:

[A.FooMonths] 

oder ähnliche

+0

Warte, was? Wie? Was für eine Art von Kompilierer ist das? – Jon

+0

Hmmm ... und ich frage mich: Was passiert, wenn Sie in einem reinen Reflektionskontext reflektieren? – Jon

+1

@Jon ja, dann bist du erledigt. Die Metadaten wissen überhaupt nichts darüber, was im Inneren passiert. Wenn Sie nur Zugriff auf Metadaten haben, können Sie nur sagen: "Es gibt ein' AwesomeFooAttribute', das ich erkennen kann, ist selbst ein 'FooAttribute'". Die meisten Menschen arbeiten jedoch nicht in reinen Reflektionskontexten. Wie es passiert, mache ich eine Menge davon (über IKVM.Reflection, in der Regel) - und ich fühle deinen Schmerz :) –

2

Short Antwort: Nr.

Aber Sie können auf das int-Array mit dem Schlüssel verweisen:

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}