7

If I want a bunch of classes to implement a method, I can just make them implement an interface. However, if I want the method to always be decorated with two custom attributes, if there a syntax for that? In other words, I want every class that implement method Run() to attach a descriptionAttribute and a versionAttribute.

Update: Is there a way to make classes that implement Run() generate a compile error if they did not attach the two attributes?

russ
  • 81
  • 2
  • you shouldn't need to worry about compile errors since those attributes will always be there in the base class – hunter Aug 19 '10 at 18:36

5 Answers5

6
public interface IRun
{
    void Run();
}

public abstract class RunBase : IRun
{
    [Description("Run Run Run")]
    [Version("1.0")]
    public abstract void Run();
}

public abstract class SoRunning : RunBase
{
    public override void Run() {} 
}

you should be able to get the Attributes off of the base class

hunter
  • 62,308
  • 19
  • 113
  • 113
  • 3
    If you have an abstract class, why do you need the interface too? – Juliet Aug 19 '10 at 14:24
  • 2
    @Juliet -- doing it this way won't impact the rest of your code, assuming you're programming to the interface IRun. – Dr Herbie Aug 19 '10 at 14:35
  • You should remove the `{}` and replace with `;` in the abstract run method in RunBase – Ben Robinson Aug 19 '10 at 14:36
  • +1, This is a good solution but not foolproof. The derived class can add new versions of the attributes with different incorrect values. – JaredPar Aug 19 '10 at 15:13
  • I'm *assuming* that the attribute values will be different for each implementation. If that assumtpation is right this solution has no benifit. – Jerod Houghtelling Aug 19 '10 at 15:47
  • @Jerod - I would disagree that, if the sub class had its own attributes how would that affect anything? It would allow them to be "upgraded". – hunter Aug 19 '10 at 18:38
  • Well I see two potential problems with the base class. The first is that while this approach guarantees that the two attributes will exist, it doesn’t guarantee that the values will be correct. Again I’m *assuming* that they user wants a compile time check because the values of the attributes are important. In that case, you would want to define them for each instance. The second is that it may be a inheritance nightmare if the class is already inheriting from a base class. Again both of these are assumptions because we don't have a lot of information to go off of. – Jerod Houghtelling Aug 19 '10 at 19:27
3

There is no compile time way to enforce that.

Yuriy Faktorovich
  • 67,283
  • 14
  • 105
  • 142
3

Maybe you should consider using abstract classes ? http://msdn.microsoft.com/en-us/library/k535acbf%28VS.71%29.aspx

(Not sure I understood your question well)

Shahor
  • 365
  • 1
  • 2
  • 10
1

I don't think there is built in compile time support. However one way you could get around this is to create a program or script that is ran at compile time by using the projects build events.

For example:

  1. Create a small program that through the commandline will take in a file path to an assembly.
  2. Make the program load the assembly from the command line
  3. Get all types out of the assembly
  4. Verify that all of the types that implement your interface have the attributes set
  5. Have the program throw an exception if conditions are not met otherwise it runs successfully
  6. Add the program to the post-build event commands through the project properties

Note: This could also be done as a 'unit' test.

Jerod Houghtelling
  • 4,783
  • 1
  • 22
  • 30
0

You could use an abstract class to validate the attributes when the class is initialized.

abstract class MustImpliment
{
    protected MustImpliment()
    {
        object[] attributes = this.GetType().GetCustomAttributes(typeof(DescriptionAttribute), true);

        if (attributes == null || attributes.Length == 0)
            throw new NotImplementedException("Pick a better exception");
    }

    // Must impliment DescriptionAttribute
    public abstract void DoSomething();
}

class DidntImpliment : MustImpliment
{
    public override void DoSomething()
    {
        // ...
    }
}

Update: This will not cause a compiler error, but you can use this as part of a Unit Test as Jerod Houghtelling suggested.

chilltemp
  • 8,854
  • 8
  • 41
  • 46
  • One problem I see with this is the multiple inheritance issue. If the class is already inheriting from an object then it might not be appropriate to insert the `MustImpliment` into the chain whereever that location might be. – Jerod Houghtelling Aug 19 '10 at 15:43