Dlaczego C# zabrania generycznych typów atrybutów?

To powoduje wyjątek w czasie kompilacji:

public sealed class ValidatesAttribute<T> : Attribute
{

}

[Validates<string>]
public static class StringValidation
{

}

Zdaję sobie sprawę, że C# nie obsługuje atrybutów generycznych. Jednak po wielu Googlach nie mogę znaleźć przyczyny.

Czy ktoś wie dlaczego typy generyczne nie mogą wywodzić się z Attribute? Jakieś teorie?

Author: Deduplicator, 2008-11-16

6 answers

Cóż, nie mogę odpowiedzieć, dlaczego nie jest dostępny, ale Mogę potwierdzić, że nie jest to problem z CLI. CLI spec o tym nie wspomina (z tego co widzę) i jeśli używasz IL bezpośrednio możesz utworzyć generyczny atrybut. Część specyfikacji C # 3, która ją zakazuje-sekcja 10.1.4 "Class base specification" nie daje żadnego uzasadnienia.

Adnotowana Specyfikacja ECMA C# 2 również nie daje żadnych przydatnych informacji, chociaż dostarcza przykład tego, co nie jest dozwolone.

My Kopia specyfikacji C # 3 powinna pojawić się jutro... Zobaczę, czy to da więcej informacji. W każdym razie, jest to zdecydowanie decyzja językowa, a nie runtime.

EDIT: odpowiedź Erica Lipperta (parafrazowana): nie ma szczególnego powodu, poza uniknięciem złożoności zarówno języka, jak i kompilatora dla przypadku użycia, który nie dodaje wiele wartości.

 314
Author: Jon Skeet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-18 15:46:27

Atrybut dekoruje klasę podczas kompilacji, ale Klasa generyczna nie otrzymuje informacji o końcowym typie do czasu uruchomienia. Ponieważ atrybut może wpływać na kompilację, musi być "kompletny" w czasie kompilacji.

Zobacz ten artykuł MSDN Aby uzyskać więcej informacji.

 73
Author: GalacticCowboy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-16 19:09:59

Nie wiem, dlaczego nie jest to dozwolone, ale jest to możliwe obejście

[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
{
    ....
}
 17
Author: GeekyMonkey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-16 21:45:03

To nie jest tak naprawdę ogólne i nadal musisz napisać specyficzną klasę atrybutów dla typu, ale możesz być w stanie użyć ogólnego interfejsu bazowego do kodowania trochę defensywnie, napisać mniejszy Kod niż jest to wymagane, uzyskać korzyści z polimorfizmu itp.

//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
{

}
 11
Author: nawfal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-07 06:45:46

To bardzo dobre pytanie. Z mojego doświadczenia z atrybutami, myślę, że ograniczenie jest na miejscu, ponieważ rozważając atrybut stworzyłby warunek, w którym musiałbyś sprawdzić wszystkie możliwe permutacje typu: typeof(Validates<string>), typeof(Validates<SomeCustomType>), itd...

Moim zdaniem, jeśli Walidacja niestandardowa jest wymagana w zależności od typu, atrybut może nie być najlepszym podejściem.

Być może Klasa walidacji, która przyjmuje SomeCustomValidationDelegate lub ISomeCustomValidator jako parametr, byłaby lepsza podejdźcie.

 8
Author: ichiban,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-16 19:15:04

Moje obejście Jest Takie:

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; }
 1
Author: razon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-29 06:56:01