9

I want to write my enum with custom attributes, for example:

public enum SomeEnum: long
{
    [SomeAttribute<MyClass1>]
    Sms = 1,
    [SomeAttribute<MyClass2>]
    Email = 2
}

but attributes doesn't support generics. Well, the most similar solution is:

public enum SomeEnum: long
{
    [SomeAttribute(typeof(MyClass1))]
    Sms = 1,
    [SomeAttribute(typeof(MyClass2))]
    Email = 2
}

And here is problem: I want Class1 to be inherited from ICustomInterface, so with generics I can write constraint:

[AttributeUsage(AttributeTargets.All)]
class SomeAttribute<T> : Attribute where T: ICustomInterface
{
}

but attributes doesn't support generics.

so finally question is: how can I check in compile time (like T constraints) that type is implementing some interface?

Alex Zhukovskiy
  • 9,565
  • 11
  • 75
  • 151
  • I think in this case the easiest way is using [`Type.GetInterface`](http://msdn.microsoft.com/en-us/library/tcctb9t8(v=vs.110).aspx) - but are you sure that you need this inside the *attribute*? I would guess it's more handy where you *do something* with classes having this attribute... – Random Dev Oct 23 '14 at 05:19
  • I'm sure that I need a constraint on this type. It's logicaly sort of `AttributeUsage`. In runtime I can check by using `IsAssignableFrom`, but it's runtime validation. – Alex Zhukovskiy Oct 23 '14 at 05:34
  • The Attribute stuff is always runtime - the few exceptions to that (AttributeUsage, etc) are IMO hard-coded into the compiler. – Random Dev Oct 23 '14 at 06:30
  • 2
    By putting this behaviour into an attribute you are making it very hard to test, and that alone should be a warning sign. Consider making an `IValidator` interface (and assorted implementations) instead. An attribute cannot be used in the way that you want to achieve. – Dan Oct 23 '14 at 07:37
  • 1
    Unfortunately what you are trying to do is not possible at compile time (w/ the current version of .net). You can only evaluate method (and constructor) parameters at run time. And as you pointed out, you can't use generic attributes: http://stackoverflow.com/questions/294216/why-does-c-sharp-forbid-generic-attribute-types – Philip Pittle Oct 23 '14 at 10:24
  • In fact, I think this is essentially a duplicate of: http://stackoverflow.com/questions/294216/why-does-c-sharp-forbid-generic-attribute-types – Philip Pittle Oct 23 '14 at 10:25
  • @PhilipPittle "Why" != "How to avoid". I learned all this posts before posting my own. – Alex Zhukovskiy Oct 23 '14 at 11:33
  • @AlexJoukovsky, point taken. Unfortunately than it's not possible (as the answers have pointed out). Hopefully the C# language designers will add it soon though. – Philip Pittle Oct 23 '14 at 13:54
  • 1
    @PhilipPittle it seems to be truth, I mean ruyJIT, Rosylin and VS2014. Well, we can do nothing at now and should only wait – Alex Zhukovskiy Oct 23 '14 at 14:23

2 Answers2

8

Very simple to your final question:

so finally question is: how can I check in compile time (like T constraints) that type is implementing some interface?

You can not do that.

But you can check it at runtime, with some reflection methods like: Type.IsAssignableFrom

BendEg
  • 20,098
  • 17
  • 57
  • 131
1

While i've had similar problems you won't get compile time checking for this.

For now this:

public class SomeAttribute : Attribute
{
    public SomeAttribute(Type given)
    {
        Given = given;
        Required = typeof (INotifyDataErrorInfo);
    }

    public Type Given { get; set; }
    public Type Required { get; set; }

    public bool Valid()
    {
        return Required.IsAssignableFrom(Given);
    }
}

public enum TestEnum 
{
    [Some(typeof(string))]
    Sms = 1,
    [Some(typeof(string))]
    Email = 2
}

Is far as you're gonna get sadly.

Though as far as i can recall, if you use PostSharp there is a way to invoke code dependant compile time checks if that's what you're after. That may not point out flaws visually in your IDE, but it still ensures that other devs have to ensure that a certain type is passed.

Dbl
  • 5,634
  • 3
  • 41
  • 66