views:

3649

answers:

4

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?

+8  A: 

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.

GalacticCowboy
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?
Bryan Watts
Bryan: I can ask the C# team if you're interested... no guarantee of an answer, but we can hope.
Jon Skeet
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... :)
GalacticCowboy
Thanks for the clarification. I am going to leave the question open at this point. I voted for you :-)
Bryan Watts
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."
GalacticCowboy
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.
GalacticCowboy
Small world. I was just wondering this a few minutes ago. It would be really handy to me if support magically appeared! :-)
Peter Mounce
+3  A: 

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.

ichiban
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.
Bryan Watts
+1 That is probably the reason. Good one.
Jonathan C Dickinson
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).
bamccaig
+26  A: 

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.

Jon Skeet
I'm glad to hear generic attributes are legal IL. I would very much appreciate if you could ask the team! I had the chance to ask Anders at PDC and totally forgot :-)
Bryan Watts
I've asked... we'll see if they reply.
Jon Skeet
Thanks for the inside info!
Bryan Watts
"except to avoid complexity in both the language and compiler"...and that from the people giving us co and contravariance...
flq
Just wanted to ask the same question about attributes. Too sad generic attributes aren't available. Even worse that there is no particular reason for that. :/
Arnis L.
"use case which doesn't add much value"? That's a subjective opinion, it could provide me a lot of value!
Jon Kruger
It would value for me also as I'm finding out there's no way around this limitation.
Chris Marisic
I really have to say, this “use case which doesn’t add much value” is by far the most annoying and vexing thing I’ve heard from Eric Lippert. I’d even go so far as to say that it’s presumptuous. Who is he to say this, contrary to all the input from actual C# users worldwide? (Of course, C# is still a brilliant product overall, though.)
Timwi
@Timwi: Who is he to say this? He's one of the language designers - it's his *job* to make decisions like this. He has to judge which of the *many* new possible features will have the most positive impact on users. Finite resources, high cost of design/implementation/test, etc.
Jon Skeet
@Jon Skeet: Exactly — it is his job to *judge* this. But what he seems to do instead is *guess*. He should provide evidence that his judgement is reasonable, e.g. the results of a representative survey, or some enlightening arguments as to why we’re all wrong when we think we need the feature, but he has provided neither.
Timwi
@Timwi: I don't think Eric has any particular duty to account for every decision the design team makes. Eric puts a lot of time into explaining design decisions, but there certainly isn't enough time to give details of every single rejected feature.
Jon Skeet
@Jon Skeet: No-where did I ever mention “every single rejected feature”. This is a very popular one that is being brought up all over the place, left and right.
Timwi
@Timwi: That's news to me. I don't think I've seen it anywhere other than here.
Jon Skeet
@Timwi, Since Eric doesn't work for you I think he doesn't need to justify to you why he rejected a feature. Now me on the other hand.... I own some MSFT, so I'll bring this up in the next share holders meeting;)
tster
+2  A: 

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
{
    ....
}
GeekyMonkey
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).
Bryan Watts
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.
Chris Marisic