557

This causes a compile-time exception:

public sealed class ValidatesAttribute<T> : Attribute { } [Validates<string>] public static class StringValidation { } 

I realize C# does not support generic attributes. However, after much Googling, I can't seem to find the reason.

Does anyone know why generic types cannot derive from Attribute? Any theories?

9
  • 18
    You could do [Validates(typeof(string)] - I agree generics would be nicer... Commented Mar 1, 2010 at 19:43
  • 22
    Even though this is a very late addition to this question, it's sad that not only attributes themselves but also abstract attribute classes (which obviously cannot be instantiated as attributes anyways) aren't allwed, like this: abstract class Base<T>: Attribute {} which could be used to create non-generic derived classes like this: class Concrete: Base<MyType> {} Commented May 19, 2010 at 18:46
  • 97
    I crave for generic attributes and attributes accepting lambdas. Imagine things like [DependsOnProperty<Foo>(f => f.Bar)] or [ForeignKey<Foo>(f => f.IdBar)]... Commented Aug 10, 2011 at 19:39
  • 3
    This would be extremely useful in a situation I just encountered; it would be nice to create a LinkedValueAttribute that accepted a generic type and enforced that type on the actual value specified. I could use it for enums to specify the "default" value of another enum that should be used if this enum value is chosen. Multiple of these attributes could be specified for different types, and I could get the value I need based on the type I need. I can set it up to use Type and Object but being strongly typed would be a huge plus. Commented Aug 22, 2012 at 18:42
  • 10
    If you don't mind a little IL, this looks promising. Commented Oct 9, 2012 at 18:39

8 Answers 8

386

Well, I can't answer why it's not available, but I can confirm that it's not a CLI issue. The CLI spec doesn't mention it (as far as I can see) and if you use IL directly you can create a generic attribute. The part of the C# 3 spec that bans it - section 10.1.4 "Class base specification" doesn't give any justification.

The annotated ECMA C# 2 spec doesn't give any helpful information either, although it does provide an example of what's not allowed.

My copy of the annotated C# 3 spec should arrive tomorrow... I'll see if that gives any more information. Anyway, it's definitely a language decision rather than a runtime one.

EDIT: Answer from Eric Lippert (paraphrased): no particular reason, except to avoid complexity in both the language and compiler for a use case which doesn't add much value.

Sign up to request clarification or add additional context in comments.

25 Comments

"except to avoid complexity in both the language and compiler"...and that from the people giving us co and contravariance...
"use case which doesn't add much value"? That's a subjective opinion, it could provide me a lot of value!
The thing that bothers me the most about not having this feature, is not being able to do stuff like [PropertyReference(x => x.SomeProperty)]. Instead, you need magic strings and typeof(), which I think kind of sucks.
@John: I think you vastly underestimate the cost of designing, specifying, implementing and testing a new language feature.
I just want to add in @Timwi's defence that this isn't quite the only place they are being discussed, and the 13K views on this question implies a healthy level of interest. Also: thanks for getting an authoritative answer, Jon.
|
93

An attribute decorates a class at compile-time, but a generic class does not receive its final type information until runtime. Since the attribute can affect compilation, it has to be "complete" at compile time.

See this MSDN article for more information.

6 Comments

The article restates that they are not possible, but without reason. I conceptually understand your answer. Do you know of any more official documentation on the issue?
The article does cover the fact that the IL still contains generic placeholders that are substituted with the actual type at runtime. The rest was inferred by me... :)
For what it's worth, VB enforces the same constraint: "Classes that are generic or contained in a generic type cannot inherit from an attribute class."
ECMA-334, section 14.16 says "Constant expressions are required in the contexts listed below and this is indicated in the grammar by using constant-expression. In these contexts, a compile-time error occurs if an expression cannot be fully evaluated at compile-time." Attributes are in the list.
This seems to be contradicted by another answer which states that IL will allow it. (stackoverflow.com/a/294259/3195477)
|
24

Generic Attributes are available since C# 11. Now, this is possible:

[GenericAttribute<int>()] public int Method(); 

However, this is not possible yet:

[GenericAttribute<T>()] public int Method<T>(T param); 

T is not known at compile time.

Also,

The type arguments must satisfy the same restrictions as the typeof operator. Types that require metadata annotations aren't allowed. For example, the following types aren't allowed as the type parameter:

  • dynamic
  • string? (or any nullable reference type)
  • (int X, int Y) (or any other tuple types using C# tuple syntax).

These types aren't directly represented in metadata. They include annotations that describe the type. In all cases, you can use the underlying type instead:

  • object for dynamic.
  • string instead of string?.
  • ValueTuple<int, int> instead of (int X, int Y).

Source: https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-11#generic-attributes

4 Comments

This is pretty great, but it does not seem to allow a parameter type Expression<Func<T, object>> (might be doing something wrong here) which means it's not possible to do something like: [Lookup<Child>(c => c.ParentId)]
14 years passed, and still not fully there yet... I think have to finally change the main programming language to something more... actively listening user voice eh
@CharlesChen I imagine that embedding lambdas may be a bit more involved, since it's pretty complex compiler part with all closures etc (of course not in this context).. If only we've had operators like methodof or if only typeof could contextually return relevant Type/MethodInfo/FieldInfo/etc. Since a System.Type could be compile-constant enough to be decided with typeof, or embedded as an attribute's parameter, why Method/Property/FieldInfo's can't? sad :(
It's a pity we can't MethodInfo = typeof(string.ToString()); and be simplify what we now do with reflection for the most of the time.... Then, simple transformation like move param expression to class Foo<>{ internal static Expr<...> _field = ...} and then [Lookup(typeof(Foo<Child>._field))] and do the value-reading from the _field in Lookup's ctor.. sounds dead simple comparing to what happens with foreach/using/yield/await/etc.. Of course I imagine the compiler has no need for such typeof since it just could bake it in like Type.. if its serializable like Type.. but probably isn't
22

I don't know why it's not allowed, but this is one possible workaround

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

7 Comments

Unfortunately, you lose compile-time typing when consuming the attribute. Imagine the attribute creates something of the generic type. You can work around it, but it would be nice; it's one of those intuitive things you're surprised you can't do, like variance (currently).
Sadly trying to not do this is why I found this SO question. I guess I'll just have to stick with dealing with typeof. It really feels ilke a dirty keyword now after generics have existed for so long now.
This doesn't answer the question.
As GeekyMonkey stated - this is a workaround. It's better than waiting for C# 10 - so thanks for that
@andrew.fox what in C# 10.0 fixes this?
|
18

This is not truly generic and you still have to write specific attribute class per type, but you may be able to use a generic base interface to code a little defensively, write lesser code than otherwise required, get benefits of polymorphism etc.

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

Comments

7

This is a very good question. In my experience with attributes, I think the constraint is in place because when reflecting on an attribute it would create a condition in which you would have to check for all possible type permutations: typeof(Validates<string>), typeof(Validates<SomeCustomType>), etc...

In my opinion, if a custom validation is required depending on the type, an attribute may not be the best approach.

Perhaps a validation class that takes in a SomeCustomValidationDelegate or an ISomeCustomValidator as a parameter would be a better approach.

3 Comments

I agree with you. I have had this question for a long time, and am currently building a validation system. I used my current terminology to ask the question, but have no intention of implementing an approach based on this mechanism.
I stumbled across this while working on a design for the same goal: validation. I'm trying to do it in a way that is easy to analyze both automatically (i.e., you could generate a report describing validation in the application for confirmation) and by a human visualizing the code. If not attributes, I'm not sure what the best solution would be... I might still try the attribute design, but manually declare type-specific attributes. It's a bit more work, but the aim is for the reliability of knowing the validation rules (and being able to report on them for confirmation).
you could check against the generic type definitions (i.e. typeof(Validates<>)) ...
5

This is not currently a C# language feature, however there is much discussion on the official C# language repo.

From some meeting notes:

Even though this would work in principle, there are bugs in most versions of the runtime so that it wouldn't work correctly (it was never exercised).

We need a mechanism to understand which target runtime it works on. We need that for many things, and are currently looking at that. Until then, we can't take it.

Candidate for a major C# version, if we can make a sufficient number of runtime versions deal with it.

Comments

-2

My workaround is something like this:

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

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.