Frage

Dies bewirkt eine Kompilierung-Ausnahme:

public sealed class ValidatesAttribute<T> : Attribute
{

}

[Validates<string>]
public static class StringValidation
{

}

Ich weiß, C # nicht generische Attribute unterstützt. Doch nach vielen googeln, kann ich nicht den Grund scheine zu finden.

Weiß jemand, warum generische Typen von Attribute nicht ableiten können? Irgendwelche Theorien?

War es hilfreich?

Lösung

Nun, ich kann nicht beantworten, warum es nicht möglich ist, aber ich kann bestätigen, dass es kein Problem ist CLI. Die CLI-Spezifikation nicht erwähnt, es (soweit ich sehen kann) und wenn Sie IL direkt verwenden können Sie ein allgemeines Attribut erstellen. Der Teil des C # 3 spec, die es verbietet, -. Abschnitt 10.1.4 „Klasse Base Specification“ gibt keine Begründung

Die kommentierte ECMA C # 2 spec gibt keine hilfreichen Informationen entweder, obwohl es ein Beispiel tut das, was nicht erlaubt ist.

Meine Kopie der C # 3 spec kommentierte sollte morgen kommen ... Ich werde sehen, ob das mehr Informationen gibt. Wie auch immer, es ist definitiv eine Sprache Entscheidung statt einer Laufzeit ein.

EDIT: Antwort von Eric Lippert (paraphrasiert):. Ohne besonderen Grund, außer Komplexität zu vermeiden, sowohl in der Sprache und Compiler für einen Anwendungsfall, die nicht viel Wert nicht hinzufügen

Andere Tipps

Ein Attribut ziert eine Klasse zur Compile-Zeit, aber eine generische Klasse nicht empfängt seine endgültigen Typinformationen bis zur Laufzeit. Da das Attribut Kompilation beeinflussen kann, hat es bei der Kompilierung sein „vollständig“.

Sehen Sie diese MSDN-Artikel für weitere Informationen.

Ich weiß nicht, warum es nicht erlaubt ist, aber dies ist eine mögliche Abhilfe

[AttributeUsage(AttributeTargets.Class)]
public class ClassDescriptionAttribute : Attribute
{
    public ClassDescriptionAttribute(Type KeyDataType)
    {
        _KeyDataType = KeyDataType;
    }

    public Type KeyDataType
    {
        get { return _KeyDataType; }
    }
    private Type _KeyDataType;
}


[ClassDescriptionAttribute(typeof(string))]
class Program
{
    ....
}

Dies ist nicht wirklich generisch und Sie immer noch spezifische Attributklasse pro Art zu schreiben, aber Sie können eine generische Basisschnittstelle zu verwenden, um defensiv ein wenig zu codieren, weniger Code zu schreiben, als es sonst erforderlich ist, erhalten Vorteile von Polymorphismus usw.

//an interface which means it can't have its own implementation. 
//You might need to use extension methods on this interface for that.
public interface ValidatesAttribute<T>
{
    T Value { get; } //or whatever that is
    bool IsValid { get; } //etc
}

public class ValidatesStringAttribute : Attribute, ValidatesAttribute<string>
{
    //...
}
public class ValidatesIntAttribute : Attribute, ValidatesAttribute<int>
{
    //...
}

[ValidatesString]
public static class StringValidation
{

}
[ValidatesInt]
public static class IntValidation
{

}

Dies ist eine sehr gute Frage. Nach meiner Erfahrung mit Attributen, ich denke, die Einschränkung vorhanden ist, weil, wenn auf einem Attribut reflektieren würde es einen Zustand schaffen, in dem Sie für alle mögliche Typen Permutationen müßten überprüfen: typeof(Validates<string>), typeof(Validates<SomeCustomType>), etc ...

Meiner Meinung nach, wenn eine benutzerdefinierte Validierung erforderlich ist, je nach Typ, ein Attribut kann nicht der beste Ansatz sein.

Vielleicht eine Prüfklasse das wäre in einem SomeCustomValidationDelegate oder eine ISomeCustomValidator als Parameter ein besserer Ansatz.

Meine Abhilfe ist so etwas wie folgt aus:

public class DistinctType1IdValidation : ValidationAttribute
{
    private readonly DistinctValidator<Type1> validator;

    public DistinctIdValidation()
    {
        validator = new DistinctValidator<Type1>(x=>x.Id);
    }

    public override bool IsValid(object value)
    {
        return validator.IsValid(value);
    }
}

public class DistinctType2NameValidation : ValidationAttribute
{
    private readonly DistinctValidator<Type2> validator;

    public DistinctType2NameValidation()
    {
        validator = new DistinctValidator<Type2>(x=>x.Name);
    }

    public override bool IsValid(object value)
    {
        return validator.IsValid(value);
    }
}

...
[DataMember, DistinctType1IdValidation ]
public Type1[] Items { get; set; }

[DataMember, DistinctType2NameValidation ]
public Type2[] Items { get; set; }

Dies ist nicht ein # -Sprache Merkmal C, jedoch es viel Diskussion über die offizielle Sprache C # ist Repo .

einige Besprechungsnotizen :

  

Auch wenn dies im Prinzip funktionieren würde, gibt es Fehler in den meisten   Versionen der Laufzeit, so dass es nicht richtig funktionieren würde (es war   nie ausgeübt wird).

     

Wir brauchen einen Mechanismus zu verstehen, welche Ziellaufzeit funktioniert es auf. Wir   viele Dinge müssen, dass für und sind derzeit dabei suchen. Bis   dann können wir es nicht nehmen.

     

Kandidat für eine große C # -Version, wenn wir eine ausreichende Anzahl machen   die Laufzeit beschäftigen Versionen mit.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top