Kann ich Eigenschaften in Teilklassen definieren und sie dann mit Attributen in einer anderen Teilklasse markieren?

84

Gibt es eine Möglichkeit, eine generierte Codedatei wie folgt zu erstellen:

public partial class A {
public string a {get; set;}
}

und dann in einer anderen Datei:

public partial class A {
[Attribute("etc")]
public string a {get; set;}
}

Damit ich eine Klasse aus der Datenbank generieren lassen und sie dann mit einer nicht generierten Datei markieren kann?

Chris McCall
quelle
Wie viel wird "aus der Datenbank generiert"? Nur Eigenschaftsdefinitionen oder auch Code?
Snemarch
1
Kurze Antwort, nein. Lange Antwort, dup von stackoverflow.com/questions/456624/… .
Kirk Woll
@snemarch: Nur Eigenschaftsdefinitionen. Ich plane, jeden anderen Code von Hand zu erstellen.
Chris McCall
1
Könnten Sie mit einer Aufteilung von Schnittstelle + Implementierung anstelle einer Teilklasse arbeiten? Generieren Sie die Schnittstelle aus der Datenbank, implementieren Sie (und fügen Sie Attribute hinzu) in der Implementierung.
Snemarch
Ja, das ist möglich, aber mit der Verwendung von Metadaten muss dann der andere Teil diese Metadaten erben
CyberNinja

Antworten:

33

Ich habe so etwas in einem Artikel von Scott Guthrie gesehen (gegen Ende) - habe es aber nicht selbst versucht.
http://weblogs.asp.net/scottgu/archive/2010/01/15/asp-net-mvc-2-model-validation.aspx

[MetadataType(typeof(Person_Validation))]
public partial class Person
{
    // Partial class compiled with code produced by VS designer
}

[Bind(Exclude="ID")]
public class Person_Validation
{
    [Required(ErrorMessage = "First Name Required")]
    [StringLength(50, ErrorMessage = "Must be under 50 characters")]
    public string FirstName { get; set; }

    [Required(ErrorMessage = "Last Name Required")]
    [StringLength(50, ErrorMessage = "Must be under 50 characters")]
    public string LastName { get; set; }

    [Required(ErrorMessage = "Age Required")]
    [Range(0, 120, ErrorMessage = "Age must be between 0 and 120")]
    public int Age { get; set; }

    [Required(ErrorMessage = "Email Required")]
    [Email(ErrorMessage = "Not a valid email")]
    public string Email { get; set; }
}
Dan Dumitru
quelle
10
Diese Antwort ist erwähnenswert, aber keine allgemeine Lösung für die vom OP gestellte Frage. Die Verbraucher der Attribute müssen noch wissen , für die Meta - Daten - Klasse aussehen - dh diese Attribute nicht durch Attribute.GetCustomAttribute (...) zurückgeführt werden. (Zum Glück für viele Anwendungsfälle werden die Verbraucher von MS geschrieben und in bestimmten Situationen wird dies funktionieren.)
Kirk Woll
1
Diese Lösung löst das Problem NICHT. Warum versuchen wir, Mitglieder in einer anderen Datei zu dekorieren? Weil die Klasse jedes Mal, wenn der Designer ausgeführt wird, ÜBERSCHREIBT. Somit wird Ihr Attribut [MetaDataType ...jedes Mal gelöscht, wenn der Designer ausgeführt wird
2
@Desolator - Die Idee ist, dass Sie das MetadataTypeAttribut nicht in die vom Designer generierte Datei einfügen , sondern in die andere Datei, in der die Teilklasse Persondefiniert ist.
Dan Dumitru
1
Das Problem mit dieser Lösung ist, dass die Klasse teilweise gewesen sein sollte
CyberNinja
85

Hier ist die Lösung, die ich für solche Fälle verwendet habe. Dies ist nützlich, wenn Sie automatisch generierte Klassen haben, die Sie mit Attributen dekorieren möchten. Angenommen, dies ist die automatisch generierte Klasse:

public partial class UserProfile
{
    public int UserId { get; set; }
    public string UserName { get; set; }
    public string Firstname { get; set; }
    public string Lastname { get; set; }
}

Angenommen, ich möchte ein Attribut hinzufügen, um anzugeben, dass UserId der Schlüssel ist. Ich würde dann eine Teilklasse in einer anderen Datei wie dieser erstellen:

[Table("UserProfile")]
[MetadataType(typeof(UserProfileMetadata))]
public partial class UserProfile
{
    internal sealed class UserProfileMetadata
    {
        [Key]
        [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
        public int UserId { get; set; }
    }
}
Jean-François Beauchamp
quelle
Tolle Lösung. Ich wusste, dass Sie die Teilklasse mit Attributen in mehreren Dateien dekorieren und sogar Schnittstellen und eine geerbte Klasse zu ihrer Deklaration hinzufügen können, aber ich habe keine Verbindung zum MetadataTypeAttribut hergestellt. Gut gemacht!
Pflugs
Was ist, wenn ich dem Konstruktor von ein Attribut hinzufügen möchte UserProfile?
Botis
2
MetadataTypeexistiert nicht in .NET Core
WoIIe
2
.net Kern verwendetModelMetadataType
YLJ
1
@ Dave Support soll in .NET Core 3.0
Roger Willcocks
2

Dies ist meine Antwort auf
verschiedene Klassendateien, oder Sie können die Metadaten in derselben Datei kombinieren, aber den Namespace beibehalten. So können sie sich offensichtlich sehen.

Denken Sie daran, wenn Sie Ihr Modell aktualisieren, z. B. indem Sie weitere Spalten hinzufügen, müssen Sie auch die Projektklasse aktualisieren.

--your model class
public partial class A {
    public string a {get; set;}
}

--your project class 
public class Ametadata {
     [Attribute("etc")]
     public string a {get; set;}
}


[MetadataType(typeof(Ametadata))]
public partial class A
{
}
CyberNinja
quelle
1

Sie müssen eine Teilklasse für Ihre AKlasse wie im folgenden Beispiel definieren

using System.ComponentModel.DataAnnotations;

// your auto-generated partial class
public partial class A 
{
    public string MyProp { get; set; }
}

[MetadataType(typeof(AMetaData))]
public partial class A 
{

}

public class AMetaData
{
    [System.ComponentModel.DefaultValue(0)]
    public string MyProp { get; set; }
}
Masoud Darvishian
quelle
0

Nicht als solches; Der Compiler wird sich beschweren, dass das Mitglied in mehreren Teilen definiert ist. Da die Verwendung von benutzerdefinierten Attributen jedoch reflektierender Natur ist, können Sie eine "Metadaten" -Klasse definieren und sie zum Enthalten von Dekoratoren verwenden.

public class A
{
   public string MyString;
}

public class AMeta
{
   [TheAttribute("etc")]
   public object MyString;
}

...

var myA = new A();
var metaType = Type.GetType(myA.GetType().Name + "Meta");
var attributesOfMyString = metaType.GetMember("MyString").GetCustomAttributes();
KeithS
quelle
1
Wie oft ist es der Schauspieler, der die Attribute zu seinen Eigenschaften hinzufügt, auch derjenige, der sie konsumiert und daher weiß, nach den magischen "Meta" -Klassen zu suchen?
Kirk Woll
Nach meiner Erfahrung sehr oft. Dies würde für ein vorhandenes aspektorientiertes Framework nicht funktionieren. Wenn Sie jedoch Ihre Domain beispielsweise mit benutzerdefinierten Validierungsattributen dekorieren, suchen Sie nach diesen und können definieren, wo. Mein Team hat genau dies bei einem unserer Projekte getan. Der Hauptnachteil besteht darin, nicht nach der anderen Klasse zu suchen; Während der Entwicklung werden zwei parallele Klassen beibehalten, eine funktionale und eine dekorative. Dies wäre auch in Teilklassen ein Problem, wenn Sie zunächst Teilfelder / -eigenschaften definieren könnten.
KeithS