2010-05-19 3 views
14

Ich möchte ein benutzerdefiniertes Attribut erstellen, die wie auf einer Eigenschaft verwendet werden können:Wie erhält und ändert man einen Eigenschaftswert über ein benutzerdefiniertes Attribut?

[TrimInputString] 
public string FirstName { get; set; } 

das funktionale Äquivalent von

private string _firstName 
public string FirstName { 
    set { 
    _firstName = value.Trim(); 
    } 
    get { 
    return _firstName; 
    } 
} 

wird so sein wird grundsätzlich jedes Mal Eigenschaft den Wert getrimmt werden .

Wie bekomme ich den Wert analysiert, ändern Sie diesen Wert und legen Sie die Eigenschaft mit dem neuen Wert alle innerhalb des Attributs?

[AttributeUsage(AttributeTargets.Property)] 
public class TrimInputAttribute : Attribute { 

    public TrimInputAttribute() { 
    //not sure how to get and modify the property here 
    } 

} 
+0

Ich denke, ein besserer Ansatz ist ein DataBinder: http://StackOverflow.com/a/1734025/7720 – Romias

Antwort

6

So funktionieren Attribute nicht. Sie können nicht auf alles zugreifen, an das das Attribut im Konstruktor angefügt ist.

Wenn Sie möchten, dass dies funktioniert, müssen Sie eine Art von Prozessorklasse erstellen, an die Sie das Objekt übergeben, das dann die Felder durchläuft und abhängig von den Attributen etwas tut. Die Operation, die ausgeführt werden soll, kann innerhalb des Attributs definiert werden (ein abstraktes Basisattribut ist hier praktisch), aber Sie müssen immer noch die Felder von Hand durchgehen, um die Operation anzuwenden.

1

Wie Matti darauf hingewiesen hat, funktionieren Attribute nicht so. Sie könnten jedoch die PostSharp AOP framework verwenden, um dies zu erreichen, wahrscheinlich überschreiben OnMethodBoundaryAspect. Aber das ist nicht trivial.

7

iam dies zu tun, ist nicht sehr überzeugend, aber seine Arbeit

Demo Klasse

public class User 
{ 

[TitleCase] 
public string FirstName { get; set; } 

[TitleCase] 
public string LastName { get; set; } 

[UpperCase] 
public string Salutation { get; set; } 

[LowerCase] 
public string Email { get; set; } 

} 

Schreiben Attribut für Lowercase, andere können auf ähnliche Weise geschrieben werden

public class LowerCaseAttribute : ValidationAttribute 
{ 
    protected override ValidationResult IsValid(object value, ValidationContext validationContext) 
    { 
     //try to modify text 
      try 
      { 
       validationContext 
       .ObjectType 
       .GetProperty(validationContext.MemberName) 
       .SetValue(validationContext.ObjectInstance, value.ToString().ToLower(), null); 
      } 
      catch (System.Exception) 
      {          
      } 

     //return null to make sure this attribute never say iam invalid 
     return null; 
    } 
} 

Nicht sehr elegante Art, wie das Validierungsattribut tatsächlich implementiert wird b ut es funktioniert

+0

Dies funktioniert natürlich nur, wenn Ihr Programm irgendwann Validierung für die Objekte ausführt. Interessanter Hack, aber ich würde es nicht im Produktionscode verwenden. –

+1

Vielleicht möchten Sie ValidationResult.Success; ' – Nikola

0

Dies kann mit Dado.ComponentModel.Mutations durchgeführt werden.

public class User 
{ 
    [Trim] 
    public string FirstName { get; set; } 
} 

// Then to preform mutation 
var user = new User() { 
    FirstName = " David Glenn " 
} 

new MutationContext<User>(user).Mutate(); 

können Sie mehr Dokumentation here.

+0

zurückgeben Nicht über die Lösung selbst zu urteilen. Aber der gewählte Namensraum finde ich irreführend. Mein erster Eindruck ist, dass es Teil des .Net-Frameworks selbst ist. Während es nicht ist. Warum starten Sie den Namespace nicht mit RoyDukkey.ComponentModel.Mutations und geben Sie Ihrem Namen ebenfalls einen Namen. –

+0

Ich stimme zu. Dies wurde ursprünglich als Vorschlag erstellt, wurde aber seitdem geschlossen. Ich habe noch die Zeit, den Namespace zu etwas passenderem zu ändern. – roydukkey

Verwandte Themen